diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 98d846ac..f95b6c9b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -71,7 +71,6 @@ 1. **GitHub Issues**: 对于公开的违规行为,可以在相关issue中直接指出 2. **私下联系**: 可以通过GitHub私信联系项目维护者 -3. **邮件联系**: [如果有项目邮箱地址,请在此提供] 所有报告都将得到及时和公正的处理。我们承诺保护报告者的隐私和安全。 diff --git a/changelogs/changelog.md b/changelogs/changelog.md index c12e726b..690f797d 100644 --- a/changelogs/changelog.md +++ b/changelogs/changelog.md @@ -1,5 +1,11 @@ # Changelog +## [0.11.7] - 2025-12-2 +- 增加麦麦做梦功能 + +- 添加全局记忆配置项 + + ## [0.11.6] - 2025-12-2 ### 🌟 重大更新 - 大幅提高记忆检索能力,略微提高token消耗 diff --git a/docker-compose.yml b/docker-compose.yml index 217ae187..1161e7d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,7 @@ services: # image: infinitycat/maibot:dev environment: - TZ=Asia/Shanghai -# - EULA_AGREE=1b662741904d7155d1ce1c00b3530d0d # 同意EULA +# - EULA_AGREE=99f08e0cab0190de853cb6af7d64d4de # 同意EULA # - PRIVACY_AGREE=9943b855e72199d0f5016ea39052f1b6 # 同意EULA ports: - "18001:8001" # webui端口 diff --git a/dummy b/dummy new file mode 100644 index 00000000..5cae3661 --- /dev/null +++ b/dummy @@ -0,0 +1,10 @@ +{ + "cells": [], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index fb613e19..00f91cf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ dependencies = [ "json-repair>=0.47.6", "maim-message", "matplotlib>=3.10.3", + "msgpack>=1.1.2", "numpy>=2.2.6", "openai>=1.95.0", "pandas>=2.3.1", @@ -23,6 +24,7 @@ dependencies = [ "pydantic>=2.11.7", "pypinyin>=0.54.0", "python-dotenv>=1.1.1", + "python-multipart>=0.0.20", "quick-algo>=0.1.3", "rich>=14.0.0", "ruff>=0.12.2", @@ -32,6 +34,7 @@ dependencies = [ "tomlkit>=0.13.3", "urllib3>=2.5.0", "uvicorn>=0.35.0", + "zstandard>=0.25.0", ] diff --git a/src/chat/brain_chat/PFC/action_planner.py b/src/chat/brain_chat/PFC/action_planner.py new file mode 100644 index 00000000..4770c6ce --- /dev/null +++ b/src/chat/brain_chat/PFC/action_planner.py @@ -0,0 +1,491 @@ +import time +from typing import Tuple, Optional # 增加了 Optional +from src.common.logger_manager import get_logger +from ..models.utils_model import LLMRequest +from ...config.config import global_config +from .chat_observer import ChatObserver +from .pfc_utils import get_items_from_json +from src.individuality.individuality import Individuality +from .observation_info import ObservationInfo +from .conversation_info import ConversationInfo +from src.plugins.utils.chat_message_builder import build_readable_messages + + +logger = get_logger("pfc_action_planner") + + +# --- 定义 Prompt 模板 --- + +# Prompt(1): 首次回复或非连续回复时的决策 Prompt +PROMPT_INITIAL_REPLY = """{persona_text}。现在你在参与一场QQ私聊,请根据以下【所有信息】审慎且灵活的决策下一步行动,可以回复,可以倾听,可以调取知识,甚至可以屏蔽对方: + +【当前对话目标】 +{goals_str} +{knowledge_info_str} + +【最近行动历史概要】 +{action_history_summary} +【上一次行动的详细情况和结果】 +{last_action_context} +【时间和超时提示】 +{time_since_last_bot_message_info}{timeout_context} +【最近的对话记录】(包括你已成功发送的消息 和 新收到的消息) +{chat_history_text} + +------ +可选行动类型以及解释: +fetch_knowledge: 需要调取知识或记忆,当需要专业知识或特定信息时选择,对方若提到你不太认识的人名或实体也可以尝试选择 +listening: 倾听对方发言,当你认为对方话才说到一半,发言明显未结束时选择 +direct_reply: 直接回复对方 +rethink_goal: 思考一个对话目标,当你觉得目前对话需要目标,或当前目标不再适用,或话题卡住时选择。注意私聊的环境是灵活的,有可能需要经常选择 +end_conversation: 结束对话,对方长时间没回复或者当你觉得对话告一段落时可以选择 +block_and_ignore: 更加极端的结束对话方式,直接结束对话并在一段时间内无视对方所有发言(屏蔽),当对话让你感到十分不适,或你遭到各类骚扰时选择 + +请以JSON格式输出你的决策: +{{ + "action": "选择的行动类型 (必须是上面列表中的一个)", + "reason": "选择该行动的详细原因 (必须有解释你是如何根据“上一次行动结果”、“对话记录”和自身设定人设做出合理判断的)" +}} + +注意:请严格按照JSON格式输出,不要包含任何其他内容。""" + +# Prompt(2): 上一次成功回复后,决定继续发言时的决策 Prompt +PROMPT_FOLLOW_UP = """{persona_text}。现在你在参与一场QQ私聊,刚刚你已经回复了对方,请根据以下【所有信息】审慎且灵活的决策下一步行动,可以继续发送新消息,可以等待,可以倾听,可以调取知识,甚至可以屏蔽对方: + +【当前对话目标】 +{goals_str} +{knowledge_info_str} + +【最近行动历史概要】 +{action_history_summary} +【上一次行动的详细情况和结果】 +{last_action_context} +【时间和超时提示】 +{time_since_last_bot_message_info}{timeout_context} +【最近的对话记录】(包括你已成功发送的消息 和 新收到的消息) +{chat_history_text} + +------ +可选行动类型以及解释: +fetch_knowledge: 需要调取知识,当需要专业知识或特定信息时选择,对方若提到你不太认识的人名或实体也可以尝试选择 +wait: 暂时不说话,留给对方交互空间,等待对方回复(尤其是在你刚发言后、或上次发言因重复、发言过多被拒时、或不确定做什么时,这是不错的选择) +listening: 倾听对方发言(虽然你刚发过言,但如果对方立刻回复且明显话没说完,可以选择这个) +send_new_message: 发送一条新消息继续对话,允许适当的追问、补充、深入话题,或开启相关新话题。**但是避免在因重复被拒后立即使用,也不要在对方没有回复的情况下过多的“消息轰炸”或重复发言** +rethink_goal: 思考一个对话目标,当你觉得目前对话需要目标,或当前目标不再适用,或话题卡住时选择。注意私聊的环境是灵活的,有可能需要经常选择 +end_conversation: 结束对话,对方长时间没回复或者当你觉得对话告一段落时可以选择 +block_and_ignore: 更加极端的结束对话方式,直接结束对话并在一段时间内无视对方所有发言(屏蔽),当对话让你感到十分不适,或你遭到各类骚扰时选择 + +请以JSON格式输出你的决策: +{{ + "action": "选择的行动类型 (必须是上面列表中的一个)", + "reason": "选择该行动的详细原因 (必须有解释你是如何根据“上一次行动结果”、“对话记录”和自身设定人设做出合理判断的。请说明你为什么选择继续发言而不是等待,以及打算发送什么类型的新消息连续发言,必须记录已经发言了几次)" +}} + +注意:请严格按照JSON格式输出,不要包含任何其他内容。""" + +# 新增:Prompt(3): 决定是否在结束对话前发送告别语 +PROMPT_END_DECISION = """{persona_text}。刚刚你决定结束一场 QQ 私聊。 + +【你们之前的聊天记录】 +{chat_history_text} + +你觉得你们的对话已经完整结束了吗?有时候,在对话自然结束后再说点什么可能会有点奇怪,但有时也可能需要一条简短的消息来圆满结束。 +如果觉得确实有必要再发一条简短、自然、符合你人设的告别消息(比如 "好,下次再聊~" 或 "嗯,先这样吧"),就输出 "yes"。 +如果觉得当前状态下直接结束对话更好,没有必要再发消息,就输出 "no"。 + +请以 JSON 格式输出你的选择: +{{ + "say_bye": "yes/no", + "reason": "选择 yes 或 no 的原因和内心想法 (简要说明)" +}} + +注意:请严格按照 JSON 格式输出,不要包含任何其他内容。""" + + +# ActionPlanner 类定义,顶格 +class ActionPlanner: + """行动规划器""" + + def __init__(self, stream_id: str, private_name: str): + self.llm = LLMRequest( + model=global_config.llm_PFC_action_planner, + temperature=global_config.llm_PFC_action_planner["temp"], + max_tokens=1500, + request_type="action_planning", + ) + self.personality_info = Individuality.get_instance().get_prompt(x_person=2, level=3) + self.name = global_config.BOT_NICKNAME + self.private_name = private_name + self.chat_observer = ChatObserver.get_instance(stream_id, private_name) + # self.action_planner_info = ActionPlannerInfo() # 移除未使用的变量 + + # 修改 plan 方法签名,增加 last_successful_reply_action 参数 + async def plan( + self, + observation_info: ObservationInfo, + conversation_info: ConversationInfo, + last_successful_reply_action: Optional[str], + ) -> Tuple[str, str]: + """规划下一步行动 + + Args: + observation_info: 决策信息 + conversation_info: 对话信息 + last_successful_reply_action: 上一次成功的回复动作类型 ('direct_reply' 或 'send_new_message' 或 None) + + Returns: + Tuple[str, str]: (行动类型, 行动原因) + """ + # --- 获取 Bot 上次发言时间信息 --- + # (这部分逻辑不变) + time_since_last_bot_message_info = "" + try: + bot_id = str(global_config.BOT_QQ) + if hasattr(observation_info, "chat_history") and observation_info.chat_history: + for i in range(len(observation_info.chat_history) - 1, -1, -1): + msg = observation_info.chat_history[i] + if not isinstance(msg, dict): + continue + sender_info = msg.get("user_info", {}) + sender_id = str(sender_info.get("user_id")) if isinstance(sender_info, dict) else None + msg_time = msg.get("time") + if sender_id == bot_id and msg_time: + time_diff = time.time() - msg_time + if time_diff < 60.0: + time_since_last_bot_message_info = ( + f"提示:你上一条成功发送的消息是在 {time_diff:.1f} 秒前。\n" + ) + break + else: + logger.debug( + f"[私聊][{self.private_name}]Observation info chat history is empty or not available for bot time check." + ) + except AttributeError: + logger.warning( + f"[私聊][{self.private_name}]ObservationInfo object might not have chat_history attribute yet for bot time check." + ) + except Exception as e: + logger.warning(f"[私聊][{self.private_name}]获取 Bot 上次发言时间时出错: {e}") + + # --- 获取超时提示信息 --- + # (这部分逻辑不变) + timeout_context = "" + try: + if hasattr(conversation_info, "goal_list") and conversation_info.goal_list: + last_goal_dict = conversation_info.goal_list[-1] + if isinstance(last_goal_dict, dict) and "goal" in last_goal_dict: + last_goal_text = last_goal_dict["goal"] + if isinstance(last_goal_text, str) and "分钟,思考接下来要做什么" in last_goal_text: + try: + timeout_minutes_text = last_goal_text.split(",")[0].replace("你等待了", "") + timeout_context = f"重要提示:对方已经长时间({timeout_minutes_text})没有回复你的消息了(这可能代表对方繁忙/不想回复/没注意到你的消息等情况,或在对方看来本次聊天已告一段落),请基于此情况规划下一步。\n" + except Exception: + timeout_context = "重要提示:对方已经长时间没有回复你的消息了(这可能代表对方繁忙/不想回复/没注意到你的消息等情况,或在对方看来本次聊天已告一段落),请基于此情况规划下一步。\n" + else: + logger.debug( + f"[私聊][{self.private_name}]Conversation info goal_list is empty or not available for timeout check." + ) + except AttributeError: + logger.warning( + f"[私聊][{self.private_name}]ConversationInfo object might not have goal_list attribute yet for timeout check." + ) + except Exception as e: + logger.warning(f"[私聊][{self.private_name}]检查超时目标时出错: {e}") + + # --- 构建通用 Prompt 参数 --- + logger.debug( + f"[私聊][{self.private_name}]开始规划行动:当前目标: {getattr(conversation_info, 'goal_list', '不可用')}" + ) + + # 构建对话目标 (goals_str) + goals_str = "" + try: + if hasattr(conversation_info, "goal_list") and conversation_info.goal_list: + for goal_reason in conversation_info.goal_list: + if isinstance(goal_reason, dict): + goal = goal_reason.get("goal", "目标内容缺失") + reasoning = goal_reason.get("reasoning", "没有明确原因") + else: + goal = str(goal_reason) + reasoning = "没有明确原因" + + goal = str(goal) if goal is not None else "目标内容缺失" + reasoning = str(reasoning) if reasoning is not None else "没有明确原因" + goals_str += f"- 目标:{goal}\n 原因:{reasoning}\n" + + if not goals_str: + goals_str = "- 目前没有明确对话目标,请考虑设定一个。\n" + else: + goals_str = "- 目前没有明确对话目标,请考虑设定一个。\n" + except AttributeError: + logger.warning( + f"[私聊][{self.private_name}]ConversationInfo object might not have goal_list attribute yet." + ) + goals_str = "- 获取对话目标时出错。\n" + except Exception as e: + logger.error(f"[私聊][{self.private_name}]构建对话目标字符串时出错: {e}") + goals_str = "- 构建对话目标时出错。\n" + + # --- 知识信息字符串构建开始 --- + knowledge_info_str = "【已获取的相关知识和记忆】\n" + try: + # 检查 conversation_info 是否有 knowledge_list 并且不为空 + if hasattr(conversation_info, "knowledge_list") and conversation_info.knowledge_list: + # 最多只显示最近的 5 条知识,防止 Prompt 过长 + recent_knowledge = conversation_info.knowledge_list[-5:] + for i, knowledge_item in enumerate(recent_knowledge): + if isinstance(knowledge_item, dict): + query = knowledge_item.get("query", "未知查询") + knowledge = knowledge_item.get("knowledge", "无知识内容") + source = knowledge_item.get("source", "未知来源") + # 只取知识内容的前 2000 个字,避免太长 + knowledge_snippet = knowledge[:2000] + "..." if len(knowledge) > 2000 else knowledge + knowledge_info_str += ( + f"{i + 1}. 关于 '{query}' 的知识 (来源: {source}):\n {knowledge_snippet}\n" + ) + else: + # 处理列表里不是字典的异常情况 + knowledge_info_str += f"{i + 1}. 发现一条格式不正确的知识记录。\n" + + if not recent_knowledge: # 如果 knowledge_list 存在但为空 + knowledge_info_str += "- 暂无相关知识和记忆。\n" + + else: + # 如果 conversation_info 没有 knowledge_list 属性,或者列表为空 + knowledge_info_str += "- 暂无相关知识记忆。\n" + except AttributeError: + logger.warning(f"[私聊][{self.private_name}]ConversationInfo 对象可能缺少 knowledge_list 属性。") + knowledge_info_str += "- 获取知识列表时出错。\n" + except Exception as e: + logger.error(f"[私聊][{self.private_name}]构建知识信息字符串时出错: {e}") + knowledge_info_str += "- 处理知识列表时出错。\n" + # --- 知识信息字符串构建结束 --- + + # 获取聊天历史记录 (chat_history_text) + try: + if hasattr(observation_info, "chat_history") and observation_info.chat_history: + chat_history_text = observation_info.chat_history_str + if not chat_history_text: + chat_history_text = "还没有聊天记录。\n" + else: + chat_history_text = "还没有聊天记录。\n" + + if hasattr(observation_info, "new_messages_count") and observation_info.new_messages_count > 0: + if hasattr(observation_info, "unprocessed_messages") and observation_info.unprocessed_messages: + new_messages_list = observation_info.unprocessed_messages + new_messages_str = await build_readable_messages( + new_messages_list, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + chat_history_text += ( + f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" + ) + else: + logger.warning( + f"[私聊][{self.private_name}]ObservationInfo has new_messages_count > 0 but unprocessed_messages is empty or missing." + ) + except AttributeError: + logger.warning( + f"[私聊][{self.private_name}]ObservationInfo object might be missing expected attributes for chat history." + ) + chat_history_text = "获取聊天记录时出错。\n" + except Exception as e: + logger.error(f"[私聊][{self.private_name}]处理聊天记录时发生未知错误: {e}") + chat_history_text = "处理聊天记录时出错。\n" + + # 构建 Persona 文本 (persona_text) + persona_text = f"你的名字是{self.name},{self.personality_info}。" + + # 构建行动历史和上一次行动结果 (action_history_summary, last_action_context) + # (这部分逻辑不变) + action_history_summary = "你最近执行的行动历史:\n" + last_action_context = "关于你【上一次尝试】的行动:\n" + action_history_list = [] + try: + if hasattr(conversation_info, "done_action") and conversation_info.done_action: + action_history_list = conversation_info.done_action[-5:] + else: + logger.debug(f"[私聊][{self.private_name}]Conversation info done_action is empty or not available.") + except AttributeError: + logger.warning( + f"[私聊][{self.private_name}]ConversationInfo object might not have done_action attribute yet." + ) + except Exception as e: + logger.error(f"[私聊][{self.private_name}]访问行动历史时出错: {e}") + + if not action_history_list: + action_history_summary += "- 还没有执行过行动。\n" + last_action_context += "- 这是你规划的第一个行动。\n" + else: + for i, action_data in enumerate(action_history_list): + action_type = "未知" + plan_reason = "未知" + status = "未知" + final_reason = "" + action_time = "" + + if isinstance(action_data, dict): + action_type = action_data.get("action", "未知") + plan_reason = action_data.get("plan_reason", "未知规划原因") + status = action_data.get("status", "未知") + final_reason = action_data.get("final_reason", "") + action_time = action_data.get("time", "") + elif isinstance(action_data, tuple): + # 假设旧格式兼容 + if len(action_data) > 0: + action_type = action_data[0] + if len(action_data) > 1: + plan_reason = action_data[1] # 可能是规划原因或最终原因 + if len(action_data) > 2: + status = action_data[2] + if status == "recall" and len(action_data) > 3: + final_reason = action_data[3] + elif status == "done" and action_type in ["direct_reply", "send_new_message"]: + plan_reason = "成功发送" # 简化显示 + + reason_text = f", 失败/取消原因: {final_reason}" if final_reason else "" + summary_line = f"- 时间:{action_time}, 尝试行动:'{action_type}', 状态:{status}{reason_text}" + action_history_summary += summary_line + "\n" + + if i == len(action_history_list) - 1: + last_action_context += f"- 上次【规划】的行动是: '{action_type}'\n" + last_action_context += f"- 当时规划的【原因】是: {plan_reason}\n" + if status == "done": + last_action_context += "- 该行动已【成功执行】。\n" + # 记录这次成功的行动类型,供下次决策 + # self.last_successful_action_type = action_type # 不在这里记录,由 conversation 控制 + elif status == "recall": + last_action_context += "- 但该行动最终【未能执行/被取消】。\n" + if final_reason: + last_action_context += f"- 【重要】失败/取消的具体原因是: “{final_reason}”\n" + else: + last_action_context += "- 【重要】失败/取消原因未明确记录。\n" + # self.last_successful_action_type = None # 行动失败,清除记录 + else: + last_action_context += f"- 该行动当前状态: {status}\n" + # self.last_successful_action_type = None # 非完成状态,清除记录 + + # --- 选择 Prompt --- + if last_successful_reply_action in ["direct_reply", "send_new_message"]: + prompt_template = PROMPT_FOLLOW_UP + logger.debug(f"[私聊][{self.private_name}]使用 PROMPT_FOLLOW_UP (追问决策)") + else: + prompt_template = PROMPT_INITIAL_REPLY + logger.debug(f"[私聊][{self.private_name}]使用 PROMPT_INITIAL_REPLY (首次/非连续回复决策)") + + # --- 格式化最终的 Prompt --- + prompt = prompt_template.format( + persona_text=persona_text, + goals_str=goals_str if goals_str.strip() else "- 目前没有明确对话目标,请考虑设定一个。", + action_history_summary=action_history_summary, + last_action_context=last_action_context, + time_since_last_bot_message_info=time_since_last_bot_message_info, + timeout_context=timeout_context, + chat_history_text=chat_history_text if chat_history_text.strip() else "还没有聊天记录。", + knowledge_info_str=knowledge_info_str, + ) + + logger.debug(f"[私聊][{self.private_name}]发送到LLM的最终提示词:\n------\n{prompt}\n------") + try: + content, _ = await self.llm.generate_response_async(prompt) + logger.debug(f"[私聊][{self.private_name}]LLM (行动规划) 原始返回内容: {content}") + + # --- 初始行动规划解析 --- + success, initial_result = get_items_from_json( + content, + self.private_name, + "action", + "reason", + default_values={"action": "wait", "reason": "LLM返回格式错误或未提供原因,默认等待"}, + ) + + initial_action = initial_result.get("action", "wait") + initial_reason = initial_result.get("reason", "LLM未提供原因,默认等待") + + # 检查是否需要进行结束对话决策 --- + if initial_action == "end_conversation": + logger.info(f"[私聊][{self.private_name}]初步规划结束对话,进入告别决策...") + + # 使用新的 PROMPT_END_DECISION + end_decision_prompt = PROMPT_END_DECISION.format( + persona_text=persona_text, # 复用之前的 persona_text + chat_history_text=chat_history_text, # 复用之前的 chat_history_text + ) + + logger.debug( + f"[私聊][{self.private_name}]发送到LLM的结束决策提示词:\n------\n{end_decision_prompt}\n------" + ) + try: + end_content, _ = await self.llm.generate_response_async(end_decision_prompt) # 再次调用LLM + logger.debug(f"[私聊][{self.private_name}]LLM (结束决策) 原始返回内容: {end_content}") + + # 解析结束决策的JSON + end_success, end_result = get_items_from_json( + end_content, + self.private_name, + "say_bye", + "reason", + default_values={"say_bye": "no", "reason": "结束决策LLM返回格式错误,默认不告别"}, + required_types={"say_bye": str, "reason": str}, # 明确类型 + ) + + say_bye_decision = end_result.get("say_bye", "no").lower() # 转小写方便比较 + end_decision_reason = end_result.get("reason", "未提供原因") + + if end_success and say_bye_decision == "yes": + # 决定要告别,返回新的 'say_goodbye' 动作 + logger.info( + f"[私聊][{self.private_name}]结束决策: yes, 准备生成告别语. 原因: {end_decision_reason}" + ) + # 注意:这里的 reason 可以考虑拼接初始原因和结束决策原因,或者只用结束决策原因 + final_action = "say_goodbye" + final_reason = f"决定发送告别语。决策原因: {end_decision_reason} (原结束理由: {initial_reason})" + return final_action, final_reason + else: + # 决定不告别 (包括解析失败或明确说no) + logger.info( + f"[私聊][{self.private_name}]结束决策: no, 直接结束对话. 原因: {end_decision_reason}" + ) + # 返回原始的 'end_conversation' 动作 + final_action = "end_conversation" + final_reason = initial_reason # 保持原始的结束理由 + return final_action, final_reason + + except Exception as end_e: + logger.error(f"[私聊][{self.private_name}]调用结束决策LLM或处理结果时出错: {str(end_e)}") + # 出错时,默认执行原始的结束对话 + logger.warning(f"[私聊][{self.private_name}]结束决策出错,将按原计划执行 end_conversation") + return "end_conversation", initial_reason # 返回原始动作和原因 + + else: + action = initial_action + reason = initial_reason + + # 验证action类型 (保持不变) + valid_actions = [ + "direct_reply", + "send_new_message", + "fetch_knowledge", + "wait", + "listening", + "rethink_goal", + "end_conversation", # 仍然需要验证,因为可能从上面决策后返回 + "block_and_ignore", + "say_goodbye", # 也要验证这个新动作 + ] + if action not in valid_actions: + logger.warning(f"[私聊][{self.private_name}]LLM返回了未知的行动类型: '{action}',强制改为 wait") + reason = f"(原始行动'{action}'无效,已强制改为wait) {reason}" + action = "wait" + + logger.info(f"[私聊][{self.private_name}]规划的行动: {action}") + logger.info(f"[私聊][{self.private_name}]行动原因: {reason}") + return action, reason + + except Exception as e: + # 外层异常处理保持不变 + logger.error(f"[私聊][{self.private_name}]规划行动时调用 LLM 或处理结果出错: {str(e)}") + return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" diff --git a/src/chat/brain_chat/PFC/chat_observer.py b/src/chat/brain_chat/PFC/chat_observer.py new file mode 100644 index 00000000..22cbf27d --- /dev/null +++ b/src/chat/brain_chat/PFC/chat_observer.py @@ -0,0 +1,379 @@ +import time +import asyncio +import traceback +from typing import Optional, Dict, Any, List +from src.common.logger import get_module_logger +from maim_message import UserInfo +from ...config.config import global_config +from .chat_states import NotificationManager, create_new_message_notification, create_cold_chat_notification +from .message_storage import MongoDBMessageStorage +from rich.traceback import install + +install(extra_lines=3) + +logger = get_module_logger("chat_observer") + + +class ChatObserver: + """聊天状态观察器""" + + # 类级别的实例管理 + _instances: Dict[str, "ChatObserver"] = {} + + @classmethod + def get_instance(cls, stream_id: str, private_name: str) -> "ChatObserver": + """获取或创建观察器实例 + + Args: + stream_id: 聊天流ID + private_name: 私聊名称 + + Returns: + ChatObserver: 观察器实例 + """ + if stream_id not in cls._instances: + cls._instances[stream_id] = cls(stream_id, private_name) + return cls._instances[stream_id] + + def __init__(self, stream_id: str, private_name: str): + """初始化观察器 + + Args: + stream_id: 聊天流ID + """ + self.last_check_time = None + self.last_bot_speak_time = None + self.last_user_speak_time = None + if stream_id in self._instances: + raise RuntimeError(f"ChatObserver for {stream_id} already exists. Use get_instance() instead.") + + self.stream_id = stream_id + self.private_name = private_name + self.message_storage = MongoDBMessageStorage() + + # self.last_user_speak_time: Optional[float] = None # 对方上次发言时间 + # self.last_bot_speak_time: Optional[float] = None # 机器人上次发言时间 + # self.last_check_time: float = time.time() # 上次查看聊天记录时间 + self.last_message_read: Optional[Dict[str, Any]] = None # 最后读取的消息ID + self.last_message_time: float = time.time() + + self.waiting_start_time: float = time.time() # 等待开始时间,初始化为当前时间 + + # 运行状态 + self._running: bool = False + self._task: Optional[asyncio.Task] = None + self._update_event = asyncio.Event() # 触发更新的事件 + self._update_complete = asyncio.Event() # 更新完成的事件 + + # 通知管理器 + self.notification_manager = NotificationManager() + + # 冷场检查配置 + self.cold_chat_threshold: float = 60.0 # 60秒无消息判定为冷场 + self.last_cold_chat_check: float = time.time() + self.is_cold_chat_state: bool = False + + self.update_event = asyncio.Event() + self.update_interval = 2 # 更新间隔(秒) + self.message_cache = [] + self.update_running = False + + async def check(self) -> bool: + """检查距离上一次观察之后是否有了新消息 + + Returns: + bool: 是否有新消息 + """ + logger.debug(f"[私聊][{self.private_name}]检查距离上一次观察之后是否有了新消息: {self.last_check_time}") + + new_message_exists = await self.message_storage.has_new_messages(self.stream_id, self.last_check_time) + + if new_message_exists: + logger.debug(f"[私聊][{self.private_name}]发现新消息") + self.last_check_time = time.time() + + return new_message_exists + + async def _add_message_to_history(self, message: Dict[str, Any]): + """添加消息到历史记录并发送通知 + + Args: + message: 消息数据 + """ + try: + # 发送新消息通知 + notification = create_new_message_notification( + sender="chat_observer", target="observation_info", message=message + ) + # print(self.notification_manager) + await self.notification_manager.send_notification(notification) + except Exception as e: + logger.error(f"[私聊][{self.private_name}]添加消息到历史记录时出错: {e}") + print(traceback.format_exc()) + + # 检查并更新冷场状态 + await self._check_cold_chat() + + async def _check_cold_chat(self): + """检查是否处于冷场状态并发送通知""" + current_time = time.time() + + # 每10秒检查一次冷场状态 + if current_time - self.last_cold_chat_check < 10: + return + + self.last_cold_chat_check = current_time + + # 判断是否冷场 + is_cold = ( + True + if self.last_message_time is None + else (current_time - self.last_message_time) > self.cold_chat_threshold + ) + + # 如果冷场状态发生变化,发送通知 + if is_cold != self.is_cold_chat_state: + self.is_cold_chat_state = is_cold + notification = create_cold_chat_notification(sender="chat_observer", target="pfc", is_cold=is_cold) + await self.notification_manager.send_notification(notification) + + def new_message_after(self, time_point: float) -> bool: + """判断是否在指定时间点后有新消息 + + Args: + time_point: 时间戳 + + Returns: + bool: 是否有新消息 + """ + + if self.last_message_time is None: + logger.debug(f"[私聊][{self.private_name}]没有最后消息时间,返回 False") + return False + + has_new = self.last_message_time > time_point + logger.debug( + f"[私聊][{self.private_name}]判断是否在指定时间点后有新消息: {self.last_message_time} > {time_point} = {has_new}" + ) + return has_new + + def get_message_history( + self, + start_time: Optional[float] = None, + end_time: Optional[float] = None, + limit: Optional[int] = None, + user_id: Optional[str] = None, + ) -> List[Dict[str, Any]]: + """获取消息历史 + + Args: + start_time: 开始时间戳 + end_time: 结束时间戳 + limit: 限制返回消息数量 + user_id: 指定用户ID + + Returns: + List[Dict[str, Any]]: 消息列表 + """ + filtered_messages = self.message_history + + if start_time is not None: + filtered_messages = [m for m in filtered_messages if m["time"] >= start_time] + + if end_time is not None: + filtered_messages = [m for m in filtered_messages if m["time"] <= end_time] + + if user_id is not None: + filtered_messages = [ + m for m in filtered_messages if UserInfo.from_dict(m.get("user_info", {})).user_id == user_id + ] + + if limit is not None: + filtered_messages = filtered_messages[-limit:] + + return filtered_messages + + async def _fetch_new_messages(self) -> List[Dict[str, Any]]: + """获取新消息 + + Returns: + List[Dict[str, Any]]: 新消息列表 + """ + new_messages = await self.message_storage.get_messages_after(self.stream_id, self.last_message_time) + + if new_messages: + self.last_message_read = new_messages[-1] + self.last_message_time = new_messages[-1]["time"] + + # print(f"获取数据库中找到的新消息: {new_messages}") + + return new_messages + + async def _fetch_new_messages_before(self, time_point: float) -> List[Dict[str, Any]]: + """获取指定时间点之前的消息 + + Args: + time_point: 时间戳 + + Returns: + List[Dict[str, Any]]: 最多5条消息 + """ + new_messages = await self.message_storage.get_messages_before(self.stream_id, time_point) + + if new_messages: + self.last_message_read = new_messages[-1]["message_id"] + + logger.debug(f"[私聊][{self.private_name}]获取指定时间点111之前的消息: {new_messages}") + + return new_messages + + """主要观察循环""" + + async def _update_loop(self): + """更新循环""" + # try: + # start_time = time.time() + # messages = await self._fetch_new_messages_before(start_time) + # for message in messages: + # await self._add_message_to_history(message) + # logger.debug(f"[私聊][{self.private_name}]缓冲消息: {messages}") + # except Exception as e: + # logger.error(f"[私聊][{self.private_name}]缓冲消息出错: {e}") + + while self._running: + try: + # 等待事件或超时(1秒) + try: + # print("等待事件") + await asyncio.wait_for(self._update_event.wait(), timeout=1) + + except asyncio.TimeoutError: + # print("超时") + pass # 超时后也执行一次检查 + + self._update_event.clear() # 重置触发事件 + self._update_complete.clear() # 重置完成事件 + + # 获取新消息 + new_messages = await self._fetch_new_messages() + + if new_messages: + # 处理新消息 + for message in new_messages: + await self._add_message_to_history(message) + + # 设置完成事件 + self._update_complete.set() + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]更新循环出错: {e}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") + self._update_complete.set() # 即使出错也要设置完成事件 + + def trigger_update(self): + """触发一次立即更新""" + self._update_event.set() + + async def wait_for_update(self, timeout: float = 5.0) -> bool: + """等待更新完成 + + Args: + timeout: 超时时间(秒) + + Returns: + bool: 是否成功完成更新(False表示超时) + """ + try: + await asyncio.wait_for(self._update_complete.wait(), timeout=timeout) + return True + except asyncio.TimeoutError: + logger.warning(f"[私聊][{self.private_name}]等待更新完成超时({timeout}秒)") + return False + + def start(self): + """启动观察器""" + if self._running: + return + + self._running = True + self._task = asyncio.create_task(self._update_loop()) + logger.debug(f"[私聊][{self.private_name}]ChatObserver for {self.stream_id} started") + + def stop(self): + """停止观察器""" + self._running = False + self._update_event.set() # 设置事件以解除等待 + self._update_complete.set() # 设置完成事件以解除等待 + if self._task: + self._task.cancel() + logger.debug(f"[私聊][{self.private_name}]ChatObserver for {self.stream_id} stopped") + + async def process_chat_history(self, messages: list): + """处理聊天历史 + + Args: + messages: 消息列表 + """ + self.update_check_time() + + for msg in messages: + try: + user_info = UserInfo.from_dict(msg.get("user_info", {})) + if user_info.user_id == global_config.BOT_QQ: + self.update_bot_speak_time(msg["time"]) + else: + self.update_user_speak_time(msg["time"]) + except Exception as e: + logger.warning(f"[私聊][{self.private_name}]处理消息时间时出错: {e}") + continue + + def update_check_time(self): + """更新查看时间""" + self.last_check_time = time.time() + + def update_bot_speak_time(self, speak_time: Optional[float] = None): + """更新机器人说话时间""" + self.last_bot_speak_time = speak_time or time.time() + + def update_user_speak_time(self, speak_time: Optional[float] = None): + """更新用户说话时间""" + self.last_user_speak_time = speak_time or time.time() + + def get_time_info(self) -> str: + """获取时间信息文本""" + current_time = time.time() + time_info = "" + + if self.last_bot_speak_time: + bot_speak_ago = current_time - self.last_bot_speak_time + time_info += f"\n距离你上次发言已经过去了{int(bot_speak_ago)}秒" + + if self.last_user_speak_time: + user_speak_ago = current_time - self.last_user_speak_time + time_info += f"\n距离对方上次发言已经过去了{int(user_speak_ago)}秒" + + return time_info + + def get_cached_messages(self, limit: int = 50) -> List[Dict[str, Any]]: + """获取缓存的消息历史 + + Args: + limit: 获取的最大消息数量,默认50 + + Returns: + List[Dict[str, Any]]: 缓存的消息历史列表 + """ + return self.message_cache[-limit:] + + def get_last_message(self) -> Optional[Dict[str, Any]]: + """获取最后一条消息 + + Returns: + Optional[Dict[str, Any]]: 最后一条消息,如果没有则返回None + """ + if not self.message_cache: + return None + return self.message_cache[-1] + + def __str__(self): + return f"ChatObserver for {self.stream_id}" diff --git a/src/chat/brain_chat/PFC/chat_states.py b/src/chat/brain_chat/PFC/chat_states.py new file mode 100644 index 00000000..4b839b7b --- /dev/null +++ b/src/chat/brain_chat/PFC/chat_states.py @@ -0,0 +1,290 @@ +from enum import Enum, auto +from typing import Optional, Dict, Any, List, Set +from dataclasses import dataclass +from datetime import datetime +from abc import ABC, abstractmethod + + +class ChatState(Enum): + """聊天状态枚举""" + + NORMAL = auto() # 正常状态 + NEW_MESSAGE = auto() # 有新消息 + COLD_CHAT = auto() # 冷场状态 + ACTIVE_CHAT = auto() # 活跃状态 + BOT_SPEAKING = auto() # 机器人正在说话 + USER_SPEAKING = auto() # 用户正在说话 + SILENT = auto() # 沉默状态 + ERROR = auto() # 错误状态 + + +class NotificationType(Enum): + """通知类型枚举""" + + NEW_MESSAGE = auto() # 新消息通知 + COLD_CHAT = auto() # 冷场通知 + ACTIVE_CHAT = auto() # 活跃通知 + BOT_SPEAKING = auto() # 机器人说话通知 + USER_SPEAKING = auto() # 用户说话通知 + MESSAGE_DELETED = auto() # 消息删除通知 + USER_JOINED = auto() # 用户加入通知 + USER_LEFT = auto() # 用户离开通知 + ERROR = auto() # 错误通知 + + +@dataclass +class ChatStateInfo: + """聊天状态信息""" + + state: ChatState + last_message_time: Optional[float] = None + last_message_content: Optional[str] = None + last_speaker: Optional[str] = None + message_count: int = 0 + cold_duration: float = 0.0 # 冷场持续时间(秒) + active_duration: float = 0.0 # 活跃持续时间(秒) + + +@dataclass +class Notification: + """通知基类""" + + type: NotificationType + timestamp: float + sender: str # 发送者标识 + target: str # 接收者标识 + data: Dict[str, Any] + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return {"type": self.type.name, "timestamp": self.timestamp, "data": self.data} + + +@dataclass +class StateNotification(Notification): + """持续状态通知""" + + is_active: bool = True + + def to_dict(self) -> Dict[str, Any]: + base_dict = super().to_dict() + base_dict["is_active"] = self.is_active + return base_dict + + +class NotificationHandler(ABC): + """通知处理器接口""" + + @abstractmethod + async def handle_notification(self, notification: Notification): + """处理通知""" + pass + + +class NotificationManager: + """通知管理器""" + + def __init__(self): + # 按接收者和通知类型存储处理器 + self._handlers: Dict[str, Dict[NotificationType, List[NotificationHandler]]] = {} + self._active_states: Set[NotificationType] = set() + self._notification_history: List[Notification] = [] + + def register_handler(self, target: str, notification_type: NotificationType, handler: NotificationHandler): + """注册通知处理器 + + Args: + target: 接收者标识(例如:"pfc") + notification_type: 要处理的通知类型 + handler: 处理器实例 + """ + if target not in self._handlers: + self._handlers[target] = {} + if notification_type not in self._handlers[target]: + self._handlers[target][notification_type] = [] + # print(self._handlers[target][notification_type]) + self._handlers[target][notification_type].append(handler) + # print(self._handlers[target][notification_type]) + + def unregister_handler(self, target: str, notification_type: NotificationType, handler: NotificationHandler): + """注销通知处理器 + + Args: + target: 接收者标识 + notification_type: 通知类型 + handler: 要注销的处理器实例 + """ + if target in self._handlers and notification_type in self._handlers[target]: + handlers = self._handlers[target][notification_type] + if handler in handlers: + handlers.remove(handler) + # 如果该类型的处理器列表为空,删除该类型 + if not handlers: + del self._handlers[target][notification_type] + # 如果该目标没有任何处理器,删除该目标 + if not self._handlers[target]: + del self._handlers[target] + + async def send_notification(self, notification: Notification): + """发送通知""" + self._notification_history.append(notification) + + # 如果是状态通知,更新活跃状态 + if isinstance(notification, StateNotification): + if notification.is_active: + self._active_states.add(notification.type) + else: + self._active_states.discard(notification.type) + + # 调用目标接收者的处理器 + target = notification.target + if target in self._handlers: + handlers = self._handlers[target].get(notification.type, []) + # print(handlers) + for handler in handlers: + # print(f"调用处理器: {handler}") + await handler.handle_notification(notification) + + def get_active_states(self) -> Set[NotificationType]: + """获取当前活跃的状态""" + return self._active_states.copy() + + def is_state_active(self, state_type: NotificationType) -> bool: + """检查特定状态是否活跃""" + return state_type in self._active_states + + def get_notification_history( + self, sender: Optional[str] = None, target: Optional[str] = None, limit: Optional[int] = None + ) -> List[Notification]: + """获取通知历史 + + Args: + sender: 过滤特定发送者的通知 + target: 过滤特定接收者的通知 + limit: 限制返回数量 + """ + history = self._notification_history + + if sender: + history = [n for n in history if n.sender == sender] + if target: + history = [n for n in history if n.target == target] + + if limit is not None: + history = history[-limit:] + + return history + + def __str__(self): + str = "" + for target, handlers in self._handlers.items(): + for notification_type, handler_list in handlers.items(): + str += f"NotificationManager for {target} {notification_type} {handler_list}" + return str + + +# 一些常用的通知创建函数 +def create_new_message_notification(sender: str, target: str, message: Dict[str, Any]) -> Notification: + """创建新消息通知""" + return Notification( + type=NotificationType.NEW_MESSAGE, + timestamp=datetime.now().timestamp(), + sender=sender, + target=target, + data={ + "message_id": message.get("message_id"), + "processed_plain_text": message.get("processed_plain_text"), + "detailed_plain_text": message.get("detailed_plain_text"), + "user_info": message.get("user_info"), + "time": message.get("time"), + }, + ) + + +def create_cold_chat_notification(sender: str, target: str, is_cold: bool) -> StateNotification: + """创建冷场状态通知""" + return StateNotification( + type=NotificationType.COLD_CHAT, + timestamp=datetime.now().timestamp(), + sender=sender, + target=target, + data={"is_cold": is_cold}, + is_active=is_cold, + ) + + +def create_active_chat_notification(sender: str, target: str, is_active: bool) -> StateNotification: + """创建活跃状态通知""" + return StateNotification( + type=NotificationType.ACTIVE_CHAT, + timestamp=datetime.now().timestamp(), + sender=sender, + target=target, + data={"is_active": is_active}, + is_active=is_active, + ) + + +class ChatStateManager: + """聊天状态管理器""" + + def __init__(self): + self.current_state = ChatState.NORMAL + self.state_info = ChatStateInfo(state=ChatState.NORMAL) + self.state_history: list[ChatStateInfo] = [] + + def update_state(self, new_state: ChatState, **kwargs): + """更新聊天状态 + + Args: + new_state: 新的状态 + **kwargs: 其他状态信息 + """ + self.current_state = new_state + self.state_info.state = new_state + + # 更新其他状态信息 + for key, value in kwargs.items(): + if hasattr(self.state_info, key): + setattr(self.state_info, key, value) + + # 记录状态历史 + self.state_history.append(self.state_info) + + def get_current_state_info(self) -> ChatStateInfo: + """获取当前状态信息""" + return self.state_info + + def get_state_history(self) -> list[ChatStateInfo]: + """获取状态历史""" + return self.state_history + + def is_cold_chat(self, threshold: float = 60.0) -> bool: + """判断是否处于冷场状态 + + Args: + threshold: 冷场阈值(秒) + + Returns: + bool: 是否冷场 + """ + if not self.state_info.last_message_time: + return True + + current_time = datetime.now().timestamp() + return (current_time - self.state_info.last_message_time) > threshold + + def is_active_chat(self, threshold: float = 5.0) -> bool: + """判断是否处于活跃状态 + + Args: + threshold: 活跃阈值(秒) + + Returns: + bool: 是否活跃 + """ + if not self.state_info.last_message_time: + return False + + current_time = datetime.now().timestamp() + return (current_time - self.state_info.last_message_time) <= threshold diff --git a/src/chat/brain_chat/PFC/conversation.py b/src/chat/brain_chat/PFC/conversation.py new file mode 100644 index 00000000..0bc4cae8 --- /dev/null +++ b/src/chat/brain_chat/PFC/conversation.py @@ -0,0 +1,701 @@ +import time +import asyncio +import datetime + +# from .message_storage import MongoDBMessageStorage +from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat + +# from ...config.config import global_config +from typing import Dict, Any, Optional +from ..chat.message import Message +from .pfc_types import ConversationState +from .pfc import ChatObserver, GoalAnalyzer +from .message_sender import DirectMessageSender +from src.common.logger_manager import get_logger +from .action_planner import ActionPlanner +from .observation_info import ObservationInfo +from .conversation_info import ConversationInfo # 确保导入 ConversationInfo +from .reply_generator import ReplyGenerator +from ..chat.chat_stream import ChatStream +from maim_message import UserInfo +from src.plugins.chat.chat_stream import chat_manager +from .pfc_KnowledgeFetcher import KnowledgeFetcher +from .waiter import Waiter + +import traceback +from rich.traceback import install + +install(extra_lines=3) + +logger = get_logger("pfc") + + +class Conversation: + """对话类,负责管理单个对话的状态和行为""" + + def __init__(self, stream_id: str, private_name: str): + """初始化对话实例 + + Args: + stream_id: 聊天流ID + """ + self.stream_id = stream_id + self.private_name = private_name + self.state = ConversationState.INIT + self.should_continue = False + self.ignore_until_timestamp: Optional[float] = None + + # 回复相关 + self.generated_reply = "" + + async def _initialize(self): + """初始化实例,注册所有组件""" + + try: + self.action_planner = ActionPlanner(self.stream_id, self.private_name) + self.goal_analyzer = GoalAnalyzer(self.stream_id, self.private_name) + self.reply_generator = ReplyGenerator(self.stream_id, self.private_name) + self.knowledge_fetcher = KnowledgeFetcher(self.private_name) + self.waiter = Waiter(self.stream_id, self.private_name) + self.direct_sender = DirectMessageSender(self.private_name) + + # 获取聊天流信息 + self.chat_stream = chat_manager.get_stream(self.stream_id) + + self.stop_action_planner = False + except Exception as e: + logger.error(f"[私聊][{self.private_name}]初始化对话实例:注册运行组件失败: {e}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") + raise + + try: + # 决策所需要的信息,包括自身自信和观察信息两部分 + # 注册观察器和观测信息 + self.chat_observer = ChatObserver.get_instance(self.stream_id, self.private_name) + self.chat_observer.start() + self.observation_info = ObservationInfo(self.private_name) + self.observation_info.bind_to_chat_observer(self.chat_observer) + # print(self.chat_observer.get_cached_messages(limit=) + + self.conversation_info = ConversationInfo() + except Exception as e: + logger.error(f"[私聊][{self.private_name}]初始化对话实例:注册信息组件失败: {e}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") + raise + try: + logger.info(f"[私聊][{self.private_name}]为 {self.stream_id} 加载初始聊天记录...") + initial_messages = get_raw_msg_before_timestamp_with_chat( # + chat_id=self.stream_id, + timestamp=time.time(), + limit=30, # 加载最近30条作为初始上下文,可以调整 + ) + chat_talking_prompt = await build_readable_messages( + initial_messages, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + if initial_messages: + # 将加载的消息填充到 ObservationInfo 的 chat_history + self.observation_info.chat_history = initial_messages + self.observation_info.chat_history_str = chat_talking_prompt + "\n" + self.observation_info.chat_history_count = len(initial_messages) + + # 更新 ObservationInfo 中的时间戳等信息 + last_msg = initial_messages[-1] + self.observation_info.last_message_time = last_msg.get("time") + last_user_info = UserInfo.from_dict(last_msg.get("user_info", {})) + self.observation_info.last_message_sender = last_user_info.user_id + self.observation_info.last_message_content = last_msg.get("processed_plain_text", "") + + logger.info( + f"[私聊][{self.private_name}]成功加载 {len(initial_messages)} 条初始聊天记录。最后一条消息时间: {self.observation_info.last_message_time}" + ) + + # 让 ChatObserver 从加载的最后一条消息之后开始同步 + self.chat_observer.last_message_time = self.observation_info.last_message_time + self.chat_observer.last_message_read = last_msg # 更新 observer 的最后读取记录 + else: + logger.info(f"[私聊][{self.private_name}]没有找到初始聊天记录。") + + except Exception as load_err: + logger.error(f"[私聊][{self.private_name}]加载初始聊天记录时出错: {load_err}") + # 出错也要继续,只是没有历史记录而已 + # 组件准备完成,启动该论对话 + self.should_continue = True + asyncio.create_task(self.start()) + + async def start(self): + """开始对话流程""" + try: + logger.info(f"[私聊][{self.private_name}]对话系统启动中...") + asyncio.create_task(self._plan_and_action_loop()) + except Exception as e: + logger.error(f"[私聊][{self.private_name}]启动对话系统失败: {e}") + raise + + async def _plan_and_action_loop(self): + """思考步,PFC核心循环模块""" + while self.should_continue: + # 忽略逻辑 + if self.ignore_until_timestamp and time.time() < self.ignore_until_timestamp: + await asyncio.sleep(30) + continue + elif self.ignore_until_timestamp and time.time() >= self.ignore_until_timestamp: + logger.info(f"[私聊][{self.private_name}]忽略时间已到 {self.stream_id},准备结束对话。") + self.ignore_until_timestamp = None + self.should_continue = False + continue + try: + # --- 在规划前记录当前新消息数量 --- + initial_new_message_count = 0 + if hasattr(self.observation_info, "new_messages_count"): + initial_new_message_count = self.observation_info.new_messages_count + 1 # 算上麦麦自己发的那一条 + else: + logger.warning( + f"[私聊][{self.private_name}]ObservationInfo missing 'new_messages_count' before planning." + ) + + # --- 调用 Action Planner --- + # 传递 self.conversation_info.last_successful_reply_action + action, reason = await self.action_planner.plan( + self.observation_info, self.conversation_info, self.conversation_info.last_successful_reply_action + ) + + # --- 规划后检查是否有 *更多* 新消息到达 --- + current_new_message_count = 0 + if hasattr(self.observation_info, "new_messages_count"): + current_new_message_count = self.observation_info.new_messages_count + else: + logger.warning( + f"[私聊][{self.private_name}]ObservationInfo missing 'new_messages_count' after planning." + ) + + if current_new_message_count > initial_new_message_count + 2: + logger.info( + f"[私聊][{self.private_name}]规划期间发现新增消息 ({initial_new_message_count} -> {current_new_message_count}),跳过本次行动,重新规划" + ) + # 如果规划期间有新消息,也应该重置上次回复状态,因为现在要响应新消息了 + self.conversation_info.last_successful_reply_action = None + await asyncio.sleep(0.1) + continue + + # 包含 send_new_message + if initial_new_message_count > 0 and action in ["direct_reply", "send_new_message"]: + if hasattr(self.observation_info, "clear_unprocessed_messages"): + logger.debug( + f"[私聊][{self.private_name}]准备执行 {action},清理 {initial_new_message_count} 条规划时已知的新消息。" + ) + await self.observation_info.clear_unprocessed_messages() + if hasattr(self.observation_info, "new_messages_count"): + self.observation_info.new_messages_count = 0 + else: + logger.error( + f"[私聊][{self.private_name}]无法清理未处理消息: ObservationInfo 缺少 clear_unprocessed_messages 方法!" + ) + + await self._handle_action(action, reason, self.observation_info, self.conversation_info) + + # 检查是否需要结束对话 (逻辑不变) + goal_ended = False + if hasattr(self.conversation_info, "goal_list") and self.conversation_info.goal_list: + for goal_item in self.conversation_info.goal_list: + if isinstance(goal_item, dict): + current_goal = goal_item.get("goal") + + if current_goal == "结束对话": + goal_ended = True + break + + if goal_ended: + self.should_continue = False + logger.info(f"[私聊][{self.private_name}]检测到'结束对话'目标,停止循环。") + + except Exception as loop_err: + logger.error(f"[私聊][{self.private_name}]PFC主循环出错: {loop_err}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") + await asyncio.sleep(1) + + if self.should_continue: + await asyncio.sleep(0.1) + + logger.info(f"[私聊][{self.private_name}]PFC 循环结束 for stream_id: {self.stream_id}") + + def _check_new_messages_after_planning(self): + """检查在规划后是否有新消息""" + # 检查 ObservationInfo 是否已初始化并且有 new_messages_count 属性 + if not hasattr(self, "observation_info") or not hasattr(self.observation_info, "new_messages_count"): + logger.warning( + f"[私聊][{self.private_name}]ObservationInfo 未初始化或缺少 'new_messages_count' 属性,无法检查新消息。" + ) + return False # 或者根据需要抛出错误 + + if self.observation_info.new_messages_count > 2: + logger.info( + f"[私聊][{self.private_name}]生成/执行动作期间收到 {self.observation_info.new_messages_count} 条新消息,取消当前动作并重新规划" + ) + # 如果有新消息,也应该重置上次回复状态 + if hasattr(self, "conversation_info"): # 确保 conversation_info 已初始化 + self.conversation_info.last_successful_reply_action = None + else: + logger.warning( + f"[私聊][{self.private_name}]ConversationInfo 未初始化,无法重置 last_successful_reply_action。" + ) + return True + return False + + def _convert_to_message(self, msg_dict: Dict[str, Any]) -> Message: + """将消息字典转换为Message对象""" + try: + # 尝试从 msg_dict 直接获取 chat_stream,如果失败则从全局 chat_manager 获取 + chat_info = msg_dict.get("chat_info") + if chat_info and isinstance(chat_info, dict): + chat_stream = ChatStream.from_dict(chat_info) + elif self.chat_stream: # 使用实例变量中的 chat_stream + chat_stream = self.chat_stream + else: # Fallback: 尝试从 manager 获取 (可能需要 stream_id) + chat_stream = chat_manager.get_stream(self.stream_id) + if not chat_stream: + raise ValueError(f"无法确定 ChatStream for stream_id {self.stream_id}") + + user_info = UserInfo.from_dict(msg_dict.get("user_info", {})) + + return Message( + message_id=msg_dict.get("message_id", f"gen_{time.time()}"), # 提供默认 ID + chat_stream=chat_stream, # 使用确定的 chat_stream + time=msg_dict.get("time", time.time()), # 提供默认时间 + user_info=user_info, + processed_plain_text=msg_dict.get("processed_plain_text", ""), + detailed_plain_text=msg_dict.get("detailed_plain_text", ""), + ) + except Exception as e: + logger.warning(f"[私聊][{self.private_name}]转换消息时出错: {e}") + # 可以选择返回 None 或重新抛出异常,这里选择重新抛出以指示问题 + raise ValueError(f"无法将字典转换为 Message 对象: {e}") from e + + async def _handle_action( + self, action: str, reason: str, observation_info: ObservationInfo, conversation_info: ConversationInfo + ): + """处理规划的行动""" + + logger.debug(f"[私聊][{self.private_name}]执行行动: {action}, 原因: {reason}") + + # 记录action历史 (逻辑不变) + current_action_record = { + "action": action, + "plan_reason": reason, + "status": "start", + "time": datetime.datetime.now().strftime("%H:%M:%S"), + "final_reason": None, + } + # 确保 done_action 列表存在 + if not hasattr(conversation_info, "done_action"): + conversation_info.done_action = [] + conversation_info.done_action.append(current_action_record) + action_index = len(conversation_info.done_action) - 1 + + action_successful = False # 用于标记动作是否成功完成 + + # --- 根据不同的 action 执行 --- + + # send_new_message 失败后执行 wait + if action == "send_new_message": + max_reply_attempts = 3 + reply_attempt_count = 0 + is_suitable = False + need_replan = False + check_reason = "未进行尝试" + final_reply_to_send = "" + + while reply_attempt_count < max_reply_attempts and not is_suitable: + reply_attempt_count += 1 + logger.info( + f"[私聊][{self.private_name}]尝试生成追问回复 (第 {reply_attempt_count}/{max_reply_attempts} 次)..." + ) + self.state = ConversationState.GENERATING + + # 1. 生成回复 (调用 generate 时传入 action_type) + self.generated_reply = await self.reply_generator.generate( + observation_info, conversation_info, action_type="send_new_message" + ) + logger.info( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次生成的追问回复: {self.generated_reply}" + ) + + # 2. 检查回复 (逻辑不变) + self.state = ConversationState.CHECKING + try: + current_goal_str = conversation_info.goal_list[0]["goal"] if conversation_info.goal_list else "" + is_suitable, check_reason, need_replan = await self.reply_generator.check_reply( + reply=self.generated_reply, + goal=current_goal_str, + chat_history=observation_info.chat_history, + chat_history_str=observation_info.chat_history_str, + retry_count=reply_attempt_count - 1, + ) + logger.info( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次追问检查结果: 合适={is_suitable}, 原因='{check_reason}', 需重新规划={need_replan}" + ) + if is_suitable: + final_reply_to_send = self.generated_reply + break + elif need_replan: + logger.warning( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次追问检查建议重新规划,停止尝试。原因: {check_reason}" + ) + break + except Exception as check_err: + logger.error( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次调用 ReplyChecker (追问) 时出错: {check_err}" + ) + check_reason = f"第 {reply_attempt_count} 次检查过程出错: {check_err}" + break + + # 循环结束,处理最终结果 + if is_suitable: + # 检查是否有新消息 + if self._check_new_messages_after_planning(): + logger.info(f"[私聊][{self.private_name}]生成追问回复期间收到新消息,取消发送,重新规划行动") + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"有新消息,取消发送追问: {final_reply_to_send}"} + ) + return # 直接返回,重新规划 + + # 发送合适的回复 + self.generated_reply = final_reply_to_send + # --- 在这里调用 _send_reply --- + await self._send_reply() # <--- 调用恢复后的函数 + + # 更新状态: 标记上次成功是 send_new_message + self.conversation_info.last_successful_reply_action = "send_new_message" + action_successful = True # 标记动作成功 + + elif need_replan: + # 打回动作决策 + logger.warning( + f"[私聊][{self.private_name}]经过 {reply_attempt_count} 次尝试,追问回复决定打回动作决策。打回原因: {check_reason}" + ) + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"追问尝试{reply_attempt_count}次后打回: {check_reason}"} + ) + + else: + # 追问失败 + logger.warning( + f"[私聊][{self.private_name}]经过 {reply_attempt_count} 次尝试,未能生成合适的追问回复。最终原因: {check_reason}" + ) + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"追问尝试{reply_attempt_count}次后失败: {check_reason}"} + ) + # 重置状态: 追问失败,下次用初始 prompt + self.conversation_info.last_successful_reply_action = None + + # 执行 Wait 操作 + logger.info(f"[私聊][{self.private_name}]由于无法生成合适追问回复,执行 'wait' 操作...") + self.state = ConversationState.WAITING + await self.waiter.wait(self.conversation_info) + wait_action_record = { + "action": "wait", + "plan_reason": "因 send_new_message 多次尝试失败而执行的后备等待", + "status": "done", + "time": datetime.datetime.now().strftime("%H:%M:%S"), + "final_reason": None, + } + conversation_info.done_action.append(wait_action_record) + + elif action == "direct_reply": + max_reply_attempts = 3 + reply_attempt_count = 0 + is_suitable = False + need_replan = False + check_reason = "未进行尝试" + final_reply_to_send = "" + + while reply_attempt_count < max_reply_attempts and not is_suitable: + reply_attempt_count += 1 + logger.info( + f"[私聊][{self.private_name}]尝试生成首次回复 (第 {reply_attempt_count}/{max_reply_attempts} 次)..." + ) + self.state = ConversationState.GENERATING + + # 1. 生成回复 + self.generated_reply = await self.reply_generator.generate( + observation_info, conversation_info, action_type="direct_reply" + ) + logger.info( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次生成的首次回复: {self.generated_reply}" + ) + + # 2. 检查回复 + self.state = ConversationState.CHECKING + try: + current_goal_str = conversation_info.goal_list[0]["goal"] if conversation_info.goal_list else "" + is_suitable, check_reason, need_replan = await self.reply_generator.check_reply( + reply=self.generated_reply, + goal=current_goal_str, + chat_history=observation_info.chat_history, + chat_history_str=observation_info.chat_history_str, + retry_count=reply_attempt_count - 1, + ) + logger.info( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次首次回复检查结果: 合适={is_suitable}, 原因='{check_reason}', 需重新规划={need_replan}" + ) + if is_suitable: + final_reply_to_send = self.generated_reply + break + elif need_replan: + logger.warning( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次首次回复检查建议重新规划,停止尝试。原因: {check_reason}" + ) + break + except Exception as check_err: + logger.error( + f"[私聊][{self.private_name}]第 {reply_attempt_count} 次调用 ReplyChecker (首次回复) 时出错: {check_err}" + ) + check_reason = f"第 {reply_attempt_count} 次检查过程出错: {check_err}" + break + + # 循环结束,处理最终结果 + if is_suitable: + # 检查是否有新消息 + if self._check_new_messages_after_planning(): + logger.info(f"[私聊][{self.private_name}]生成首次回复期间收到新消息,取消发送,重新规划行动") + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"有新消息,取消发送首次回复: {final_reply_to_send}"} + ) + return # 直接返回,重新规划 + + # 发送合适的回复 + self.generated_reply = final_reply_to_send + # --- 在这里调用 _send_reply --- + await self._send_reply() # <--- 调用恢复后的函数 + + # 更新状态: 标记上次成功是 direct_reply + self.conversation_info.last_successful_reply_action = "direct_reply" + action_successful = True # 标记动作成功 + + elif need_replan: + # 打回动作决策 + logger.warning( + f"[私聊][{self.private_name}]经过 {reply_attempt_count} 次尝试,首次回复决定打回动作决策。打回原因: {check_reason}" + ) + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"首次回复尝试{reply_attempt_count}次后打回: {check_reason}"} + ) + + else: + # 首次回复失败 + logger.warning( + f"[私聊][{self.private_name}]经过 {reply_attempt_count} 次尝试,未能生成合适的首次回复。最终原因: {check_reason}" + ) + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"首次回复尝试{reply_attempt_count}次后失败: {check_reason}"} + ) + # 重置状态: 首次回复失败,下次还是用初始 prompt + self.conversation_info.last_successful_reply_action = None + + # 执行 Wait 操作 (保持原有逻辑) + logger.info(f"[私聊][{self.private_name}]由于无法生成合适首次回复,执行 'wait' 操作...") + self.state = ConversationState.WAITING + await self.waiter.wait(self.conversation_info) + wait_action_record = { + "action": "wait", + "plan_reason": "因 direct_reply 多次尝试失败而执行的后备等待", + "status": "done", + "time": datetime.datetime.now().strftime("%H:%M:%S"), + "final_reason": None, + } + conversation_info.done_action.append(wait_action_record) + + elif action == "fetch_knowledge": + self.state = ConversationState.FETCHING + knowledge_query = reason + try: + # 检查 knowledge_fetcher 是否存在 + if not hasattr(self, "knowledge_fetcher"): + logger.error(f"[私聊][{self.private_name}]KnowledgeFetcher 未初始化,无法获取知识。") + raise AttributeError("KnowledgeFetcher not initialized") + + knowledge, source = await self.knowledge_fetcher.fetch(knowledge_query, observation_info.chat_history) + logger.info(f"[私聊][{self.private_name}]获取到知识: {knowledge[:100]}..., 来源: {source}") + if knowledge: + # 确保 knowledge_list 存在 + if not hasattr(conversation_info, "knowledge_list"): + conversation_info.knowledge_list = [] + conversation_info.knowledge_list.append( + {"query": knowledge_query, "knowledge": knowledge, "source": source} + ) + action_successful = True + except Exception as fetch_err: + logger.error(f"[私聊][{self.private_name}]获取知识时出错: {str(fetch_err)}") + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"获取知识失败: {str(fetch_err)}"} + ) + self.conversation_info.last_successful_reply_action = None # 重置状态 + + elif action == "rethink_goal": + self.state = ConversationState.RETHINKING + try: + # 检查 goal_analyzer 是否存在 + if not hasattr(self, "goal_analyzer"): + logger.error(f"[私聊][{self.private_name}]GoalAnalyzer 未初始化,无法重新思考目标。") + raise AttributeError("GoalAnalyzer not initialized") + await self.goal_analyzer.analyze_goal(conversation_info, observation_info) + action_successful = True + except Exception as rethink_err: + logger.error(f"[私聊][{self.private_name}]重新思考目标时出错: {rethink_err}") + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"重新思考目标失败: {rethink_err}"} + ) + self.conversation_info.last_successful_reply_action = None # 重置状态 + + elif action == "listening": + self.state = ConversationState.LISTENING + logger.info(f"[私聊][{self.private_name}]倾听对方发言...") + try: + # 检查 waiter 是否存在 + if not hasattr(self, "waiter"): + logger.error(f"[私聊][{self.private_name}]Waiter 未初始化,无法倾听。") + raise AttributeError("Waiter not initialized") + await self.waiter.wait_listening(conversation_info) + action_successful = True # Listening 完成就算成功 + except Exception as listen_err: + logger.error(f"[私聊][{self.private_name}]倾听时出错: {listen_err}") + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"倾听失败: {listen_err}"} + ) + self.conversation_info.last_successful_reply_action = None # 重置状态 + + elif action == "say_goodbye": + self.state = ConversationState.GENERATING # 也可以定义一个新的状态,如 ENDING + logger.info(f"[私聊][{self.private_name}]执行行动: 生成并发送告别语...") + try: + # 1. 生成告别语 (使用 'say_goodbye' action_type) + self.generated_reply = await self.reply_generator.generate( + observation_info, conversation_info, action_type="say_goodbye" + ) + logger.info(f"[私聊][{self.private_name}]生成的告别语: {self.generated_reply}") + + # 2. 直接发送告别语 (不经过检查) + if self.generated_reply: # 确保生成了内容 + await self._send_reply() # 调用发送方法 + # 发送成功后,标记动作成功 + action_successful = True + logger.info(f"[私聊][{self.private_name}]告别语已发送。") + else: + logger.warning(f"[私聊][{self.private_name}]未能生成告别语内容,无法发送。") + action_successful = False # 标记动作失败 + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": "未能生成告别语内容"} + ) + + # 3. 无论是否发送成功,都准备结束对话 + self.should_continue = False + logger.info(f"[私聊][{self.private_name}]发送告别语流程结束,即将停止对话实例。") + + except Exception as goodbye_err: + logger.error(f"[私聊][{self.private_name}]生成或发送告别语时出错: {goodbye_err}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") + # 即使出错,也结束对话 + self.should_continue = False + action_successful = False # 标记动作失败 + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"生成或发送告别语时出错: {goodbye_err}"} + ) + + elif action == "end_conversation": + # 这个分支现在只会在 action_planner 最终决定不告别时被调用 + self.should_continue = False + logger.info(f"[私聊][{self.private_name}]收到最终结束指令,停止对话...") + action_successful = True # 标记这个指令本身是成功的 + + elif action == "block_and_ignore": + logger.info(f"[私聊][{self.private_name}]不想再理你了...") + ignore_duration_seconds = 10 * 60 + self.ignore_until_timestamp = time.time() + ignore_duration_seconds + logger.info( + f"[私聊][{self.private_name}]将忽略此对话直到: {datetime.datetime.fromtimestamp(self.ignore_until_timestamp)}" + ) + self.state = ConversationState.IGNORED + action_successful = True # 标记动作成功 + + else: # 对应 'wait' 动作 + self.state = ConversationState.WAITING + logger.info(f"[私聊][{self.private_name}]等待更多信息...") + try: + # 检查 waiter 是否存在 + if not hasattr(self, "waiter"): + logger.error(f"[私聊][{self.private_name}]Waiter 未初始化,无法等待。") + raise AttributeError("Waiter not initialized") + _timeout_occurred = await self.waiter.wait(self.conversation_info) + action_successful = True # Wait 完成就算成功 + except Exception as wait_err: + logger.error(f"[私聊][{self.private_name}]等待时出错: {wait_err}") + conversation_info.done_action[action_index].update( + {"status": "recall", "final_reason": f"等待失败: {wait_err}"} + ) + self.conversation_info.last_successful_reply_action = None # 重置状态 + + # --- 更新 Action History 状态 --- + # 只有当动作本身成功时,才更新状态为 done + if action_successful: + conversation_info.done_action[action_index].update( + { + "status": "done", + "time": datetime.datetime.now().strftime("%H:%M:%S"), + } + ) + # 重置状态: 对于非回复类动作的成功,清除上次回复状态 + if action not in ["direct_reply", "send_new_message"]: + self.conversation_info.last_successful_reply_action = None + logger.debug(f"[私聊][{self.private_name}]动作 {action} 成功完成,重置 last_successful_reply_action") + # 如果动作是 recall 状态,在各自的处理逻辑中已经更新了 done_action + + async def _send_reply(self): + """发送回复""" + if not self.generated_reply: + logger.warning(f"[私聊][{self.private_name}]没有生成回复内容,无法发送。") + return + + try: + _current_time = time.time() + reply_content = self.generated_reply + + # 发送消息 (确保 direct_sender 和 chat_stream 有效) + if not hasattr(self, "direct_sender") or not self.direct_sender: + logger.error(f"[私聊][{self.private_name}]DirectMessageSender 未初始化,无法发送回复。") + return + if not self.chat_stream: + logger.error(f"[私聊][{self.private_name}]ChatStream 未初始化,无法发送回复。") + return + + await self.direct_sender.send_message(chat_stream=self.chat_stream, content=reply_content) + + # 发送成功后,手动触发 observer 更新可能导致重复处理自己发送的消息 + # 更好的做法是依赖 observer 的自动轮询或数据库触发器(如果支持) + # 暂时注释掉,观察是否影响 ObservationInfo 的更新 + # self.chat_observer.trigger_update() + # if not await self.chat_observer.wait_for_update(): + # logger.warning(f"[私聊][{self.private_name}]等待 ChatObserver 更新完成超时") + + self.state = ConversationState.ANALYZING # 更新状态 + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]发送消息或更新状态时失败: {str(e)}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") + self.state = ConversationState.ANALYZING + + async def _send_timeout_message(self): + """发送超时结束消息""" + try: + messages = self.chat_observer.get_cached_messages(limit=1) + if not messages: + return + + latest_message = self._convert_to_message(messages[0]) + await self.direct_sender.send_message( + chat_stream=self.chat_stream, content="TODO:超时消息", reply_to_message=latest_message + ) + except Exception as e: + logger.error(f"[私聊][{self.private_name}]发送超时消息失败: {str(e)}") diff --git a/src/chat/brain_chat/PFC/conversation_info.py b/src/chat/brain_chat/PFC/conversation_info.py new file mode 100644 index 00000000..04524b69 --- /dev/null +++ b/src/chat/brain_chat/PFC/conversation_info.py @@ -0,0 +1,10 @@ +from typing import Optional + + +class ConversationInfo: + def __init__(self): + self.done_action = [] + self.goal_list = [] + self.knowledge_list = [] + self.memory_list = [] + self.last_successful_reply_action: Optional[str] = None diff --git a/src/chat/brain_chat/PFC/message_sender.py b/src/chat/brain_chat/PFC/message_sender.py new file mode 100644 index 00000000..12c2143e --- /dev/null +++ b/src/chat/brain_chat/PFC/message_sender.py @@ -0,0 +1,81 @@ +import time +from typing import Optional +from src.common.logger import get_module_logger +from ..chat.chat_stream import ChatStream +from ..chat.message import Message +from maim_message import UserInfo, Seg +from src.plugins.chat.message import MessageSending, MessageSet +from src.plugins.chat.message_sender import message_manager +from ..storage.storage import MessageStorage +from ...config.config import global_config +from rich.traceback import install + +install(extra_lines=3) + + +logger = get_module_logger("message_sender") + + +class DirectMessageSender: + """直接消息发送器""" + + def __init__(self, private_name: str): + self.private_name = private_name + self.storage = MessageStorage() + + async def send_message( + self, + chat_stream: ChatStream, + content: str, + reply_to_message: Optional[Message] = None, + ) -> None: + """发送消息到聊天流 + + Args: + chat_stream: 聊天流 + content: 消息内容 + reply_to_message: 要回复的消息(可选) + """ + try: + # 创建消息内容 + segments = Seg(type="seglist", data=[Seg(type="text", data=content)]) + + # 获取麦麦的信息 + bot_user_info = UserInfo( + user_id=global_config.BOT_QQ, + user_nickname=global_config.BOT_NICKNAME, + platform=chat_stream.platform, + ) + + # 用当前时间作为message_id,和之前那套sender一样 + message_id = f"dm{round(time.time(), 2)}" + + # 构建消息对象 + message = MessageSending( + message_id=message_id, + chat_stream=chat_stream, + bot_user_info=bot_user_info, + sender_info=reply_to_message.message_info.user_info if reply_to_message else None, + message_segment=segments, + reply=reply_to_message, + is_head=True, + is_emoji=False, + thinking_start_time=time.time(), + ) + + # 处理消息 + await message.process() + + # 不知道有什么用,先留下来了,和之前那套sender一样 + _message_json = message.to_dict() + + # 发送消息 + message_set = MessageSet(chat_stream, message_id) + message_set.add_message(message) + await message_manager.add_message(message_set) + await self.storage.store_message(message, chat_stream) + logger.info(f"[私聊][{self.private_name}]PFC消息已发送: {content}") + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]PFC消息发送失败: {str(e)}") + raise diff --git a/src/chat/brain_chat/PFC/message_storage.py b/src/chat/brain_chat/PFC/message_storage.py new file mode 100644 index 00000000..cd6a01e3 --- /dev/null +++ b/src/chat/brain_chat/PFC/message_storage.py @@ -0,0 +1,119 @@ +from abc import ABC, abstractmethod +from typing import List, Dict, Any +from src.common.database import db + + +class MessageStorage(ABC): + """消息存储接口""" + + @abstractmethod + async def get_messages_after(self, chat_id: str, message: Dict[str, Any]) -> List[Dict[str, Any]]: + """获取指定消息ID之后的所有消息 + + Args: + chat_id: 聊天ID + message: 消息 + + Returns: + List[Dict[str, Any]]: 消息列表 + """ + pass + + @abstractmethod + async def get_messages_before(self, chat_id: str, time_point: float, limit: int = 5) -> List[Dict[str, Any]]: + """获取指定时间点之前的消息 + + Args: + chat_id: 聊天ID + time_point: 时间戳 + limit: 最大消息数量 + + Returns: + List[Dict[str, Any]]: 消息列表 + """ + pass + + @abstractmethod + async def has_new_messages(self, chat_id: str, after_time: float) -> bool: + """检查是否有新消息 + + Args: + chat_id: 聊天ID + after_time: 时间戳 + + Returns: + bool: 是否有新消息 + """ + pass + + +class MongoDBMessageStorage(MessageStorage): + """MongoDB消息存储实现""" + + async def get_messages_after(self, chat_id: str, message_time: float) -> List[Dict[str, Any]]: + query = {"chat_id": chat_id, "time": {"$gt": message_time}} + # print(f"storage_check_message: {message_time}") + + return list(db.messages.find(query).sort("time", 1)) + + async def get_messages_before(self, chat_id: str, time_point: float, limit: int = 5) -> List[Dict[str, Any]]: + query = {"chat_id": chat_id, "time": {"$lt": time_point}} + + messages = list(db.messages.find(query).sort("time", -1).limit(limit)) + + # 将消息按时间正序排列 + messages.reverse() + return messages + + async def has_new_messages(self, chat_id: str, after_time: float) -> bool: + query = {"chat_id": chat_id, "time": {"$gt": after_time}} + + return db.messages.find_one(query) is not None + + +# # 创建一个内存消息存储实现,用于测试 +# class InMemoryMessageStorage(MessageStorage): +# """内存消息存储实现,主要用于测试""" + +# def __init__(self): +# self.messages: Dict[str, List[Dict[str, Any]]] = {} + +# async def get_messages_after(self, chat_id: str, message_id: Optional[str] = None) -> List[Dict[str, Any]]: +# if chat_id not in self.messages: +# return [] + +# messages = self.messages[chat_id] +# if not message_id: +# return messages + +# # 找到message_id的索引 +# try: +# index = next(i for i, m in enumerate(messages) if m["message_id"] == message_id) +# return messages[index + 1:] +# except StopIteration: +# return [] + +# async def get_messages_before(self, chat_id: str, time_point: float, limit: int = 5) -> List[Dict[str, Any]]: +# if chat_id not in self.messages: +# return [] + +# messages = [ +# m for m in self.messages[chat_id] +# if m["time"] < time_point +# ] + +# return messages[-limit:] + +# async def has_new_messages(self, chat_id: str, after_time: float) -> bool: +# if chat_id not in self.messages: +# return False + +# return any(m["time"] > after_time for m in self.messages[chat_id]) + +# # 测试辅助方法 +# def add_message(self, chat_id: str, message: Dict[str, Any]): +# """添加测试消息""" +# if chat_id not in self.messages: +# self.messages[chat_id] = [] +# self.messages[chat_id].append(message) +# self.messages[chat_id].sort(key=lambda m: m["time"]) diff --git a/src/chat/brain_chat/PFC/observation_info.py b/src/chat/brain_chat/PFC/observation_info.py new file mode 100644 index 00000000..c7572955 --- /dev/null +++ b/src/chat/brain_chat/PFC/observation_info.py @@ -0,0 +1,389 @@ +from typing import List, Optional, Dict, Any, Set +from maim_message import UserInfo +import time +from src.common.logger import get_module_logger +from .chat_observer import ChatObserver +from .chat_states import NotificationHandler, NotificationType, Notification +from src.plugins.utils.chat_message_builder import build_readable_messages +import traceback # 导入 traceback 用于调试 + +logger = get_module_logger("observation_info") + + +class ObservationInfoHandler(NotificationHandler): + """ObservationInfo的通知处理器""" + + def __init__(self, observation_info: "ObservationInfo", private_name: str): + """初始化处理器 + + Args: + observation_info: 要更新的ObservationInfo实例 + private_name: 私聊对象的名称,用于日志记录 + """ + self.observation_info = observation_info + # 将 private_name 存储在 handler 实例中 + self.private_name = private_name + + async def handle_notification(self, notification: Notification): # 添加类型提示 + # 获取通知类型和数据 + notification_type = notification.type + data = notification.data + + try: # 添加错误处理块 + if notification_type == NotificationType.NEW_MESSAGE: + # 处理新消息通知 + # logger.debug(f"[私聊][{self.private_name}]收到新消息通知data: {data}") # 可以在需要时取消注释 + message_id = data.get("message_id") + processed_plain_text = data.get("processed_plain_text") + detailed_plain_text = data.get("detailed_plain_text") + user_info_dict = data.get("user_info") # 先获取字典 + time_value = data.get("time") + + # 确保 user_info 是字典类型再创建 UserInfo 对象 + user_info = None + if isinstance(user_info_dict, dict): + try: + user_info = UserInfo.from_dict(user_info_dict) + except Exception as e: + logger.error( + f"[私聊][{self.private_name}]从字典创建 UserInfo 时出错: {e}, 字典内容: {user_info_dict}" + ) + # 可以选择在这里返回或记录错误,避免后续代码出错 + return + elif user_info_dict is not None: + logger.warning( + f"[私聊][{self.private_name}]收到的 user_info 不是预期的字典类型: {type(user_info_dict)}" + ) + # 根据需要处理非字典情况,这里暂时返回 + return + + message = { + "message_id": message_id, + "processed_plain_text": processed_plain_text, + "detailed_plain_text": detailed_plain_text, + "user_info": user_info_dict, # 存储原始字典或 UserInfo 对象,取决于你的 update_from_message 如何处理 + "time": time_value, + } + # 传递 UserInfo 对象(如果成功创建)或原始字典 + await self.observation_info.update_from_message(message, user_info) # 修改:传递 user_info 对象 + + elif notification_type == NotificationType.COLD_CHAT: + # 处理冷场通知 + is_cold = data.get("is_cold", False) + await self.observation_info.update_cold_chat_status(is_cold, time.time()) # 修改:改为 await 调用 + + elif notification_type == NotificationType.ACTIVE_CHAT: + # 处理活跃通知 (通常由 COLD_CHAT 的反向状态处理) + is_active = data.get("is_active", False) + self.observation_info.is_cold = not is_active + + elif notification_type == NotificationType.BOT_SPEAKING: + # 处理机器人说话通知 (按需实现) + self.observation_info.is_typing = False + self.observation_info.last_bot_speak_time = time.time() + + elif notification_type == NotificationType.USER_SPEAKING: + # 处理用户说话通知 + self.observation_info.is_typing = False + self.observation_info.last_user_speak_time = time.time() + + elif notification_type == NotificationType.MESSAGE_DELETED: + # 处理消息删除通知 + message_id = data.get("message_id") + # 从 unprocessed_messages 中移除被删除的消息 + original_count = len(self.observation_info.unprocessed_messages) + self.observation_info.unprocessed_messages = [ + msg for msg in self.observation_info.unprocessed_messages if msg.get("message_id") != message_id + ] + if len(self.observation_info.unprocessed_messages) < original_count: + logger.info(f"[私聊][{self.private_name}]移除了未处理的消息 (ID: {message_id})") + + elif notification_type == NotificationType.USER_JOINED: + # 处理用户加入通知 (如果适用私聊场景) + user_id = data.get("user_id") + if user_id: + self.observation_info.active_users.add(str(user_id)) # 确保是字符串 + + elif notification_type == NotificationType.USER_LEFT: + # 处理用户离开通知 (如果适用私聊场景) + user_id = data.get("user_id") + if user_id: + self.observation_info.active_users.discard(str(user_id)) # 确保是字符串 + + elif notification_type == NotificationType.ERROR: + # 处理错误通知 + error_msg = data.get("error", "未提供错误信息") + logger.error(f"[私聊][{self.private_name}]收到错误通知: {error_msg}") + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]处理通知时发生错误: {e}") + logger.error(traceback.format_exc()) # 打印详细堆栈信息 + + +# @dataclass <-- 这个,不需要了(递黄瓜) +class ObservationInfo: + """决策信息类,用于收集和管理来自chat_observer的通知信息 (手动实现 __init__)""" + + # 类型提示保留,可用于文档和静态分析 + private_name: str + chat_history: List[Dict[str, Any]] + chat_history_str: str + unprocessed_messages: List[Dict[str, Any]] + active_users: Set[str] + last_bot_speak_time: Optional[float] + last_user_speak_time: Optional[float] + last_message_time: Optional[float] + last_message_id: Optional[str] + last_message_content: str + last_message_sender: Optional[str] + bot_id: Optional[str] + chat_history_count: int + new_messages_count: int + cold_chat_start_time: Optional[float] + cold_chat_duration: float + is_typing: bool + is_cold_chat: bool + changed: bool + chat_observer: Optional[ChatObserver] + handler: Optional[ObservationInfoHandler] + + def __init__(self, private_name: str): + """ + 手动初始化 ObservationInfo 的所有实例变量。 + """ + + # 接收的参数 + self.private_name: str = private_name + + # data_list + self.chat_history: List[Dict[str, Any]] = [] + self.chat_history_str: str = "" + self.unprocessed_messages: List[Dict[str, Any]] = [] + self.active_users: Set[str] = set() + + # data + self.last_bot_speak_time: Optional[float] = None + self.last_user_speak_time: Optional[float] = None + self.last_message_time: Optional[float] = None + self.last_message_id: Optional[str] = None + self.last_message_content: str = "" + self.last_message_sender: Optional[str] = None + self.bot_id: Optional[str] = None + self.chat_history_count: int = 0 + self.new_messages_count: int = 0 + self.cold_chat_start_time: Optional[float] = None + self.cold_chat_duration: float = 0.0 + + # state + self.is_typing: bool = False + self.is_cold_chat: bool = False + self.changed: bool = False + + # 关联对象 + self.chat_observer: Optional[ChatObserver] = None + + self.handler: ObservationInfoHandler = ObservationInfoHandler(self, self.private_name) + + def bind_to_chat_observer(self, chat_observer: ChatObserver): + """绑定到指定的chat_observer + + Args: + chat_observer: 要绑定的 ChatObserver 实例 + """ + if self.chat_observer: + logger.warning(f"[私聊][{self.private_name}]尝试重复绑定 ChatObserver") + return + + self.chat_observer = chat_observer + try: + if not self.handler: # 确保 handler 已经被创建 + logger.error(f"[私聊][{self.private_name}] 尝试绑定时 handler 未初始化!") + self.chat_observer = None # 重置,防止后续错误 + return + + # 注册关心的通知类型 + self.chat_observer.notification_manager.register_handler( + target="observation_info", notification_type=NotificationType.NEW_MESSAGE, handler=self.handler + ) + self.chat_observer.notification_manager.register_handler( + target="observation_info", notification_type=NotificationType.COLD_CHAT, handler=self.handler + ) + # 可以根据需要注册更多通知类型 + # self.chat_observer.notification_manager.register_handler( + # target="observation_info", notification_type=NotificationType.MESSAGE_DELETED, handler=self.handler + # ) + logger.info(f"[私聊][{self.private_name}]成功绑定到 ChatObserver") + except Exception as e: + logger.error(f"[私聊][{self.private_name}]绑定到 ChatObserver 时出错: {e}") + self.chat_observer = None # 绑定失败,重置 + + def unbind_from_chat_observer(self): + """解除与chat_observer的绑定""" + if ( + self.chat_observer and hasattr(self.chat_observer, "notification_manager") and self.handler + ): # 增加 handler 检查 + try: + self.chat_observer.notification_manager.unregister_handler( + target="observation_info", notification_type=NotificationType.NEW_MESSAGE, handler=self.handler + ) + self.chat_observer.notification_manager.unregister_handler( + target="observation_info", notification_type=NotificationType.COLD_CHAT, handler=self.handler + ) + # 如果注册了其他类型,也要在这里注销 + # self.chat_observer.notification_manager.unregister_handler( + # target="observation_info", notification_type=NotificationType.MESSAGE_DELETED, handler=self.handler + # ) + logger.info(f"[私聊][{self.private_name}]成功从 ChatObserver 解绑") + except Exception as e: + logger.error(f"[私聊][{self.private_name}]从 ChatObserver 解绑时出错: {e}") + finally: # 确保 chat_observer 被重置 + self.chat_observer = None + else: + logger.warning(f"[私聊][{self.private_name}]尝试解绑时 ChatObserver 不存在、无效或 handler 未设置") + + # 修改:update_from_message 接收 UserInfo 对象 + async def update_from_message(self, message: Dict[str, Any], user_info: Optional[UserInfo]): + """从消息更新信息 + + Args: + message: 消息数据字典 + user_info: 解析后的 UserInfo 对象 (可能为 None) + """ + message_time = message.get("time") + message_id = message.get("message_id") + processed_text = message.get("processed_plain_text", "") + + # 只有在新消息到达时才更新 last_message 相关信息 + if message_time and message_time > (self.last_message_time or 0): + self.last_message_time = message_time + self.last_message_id = message_id + self.last_message_content = processed_text + # 重置冷场计时器 + self.is_cold_chat = False + self.cold_chat_start_time = None + self.cold_chat_duration = 0.0 + + if user_info: + sender_id = str(user_info.user_id) # 确保是字符串 + self.last_message_sender = sender_id + # 更新发言时间 + if sender_id == self.bot_id: + self.last_bot_speak_time = message_time + else: + self.last_user_speak_time = message_time + self.active_users.add(sender_id) # 用户发言则认为其活跃 + else: + logger.warning( + f"[私聊][{self.private_name}]处理消息更新时缺少有效的 UserInfo 对象, message_id: {message_id}" + ) + self.last_message_sender = None # 发送者未知 + + # 将原始消息字典添加到未处理列表 + self.unprocessed_messages.append(message) + self.new_messages_count = len(self.unprocessed_messages) # 直接用列表长度 + + # logger.debug(f"[私聊][{self.private_name}]消息更新: last_time={self.last_message_time}, new_count={self.new_messages_count}") + self.update_changed() # 标记状态已改变 + else: + # 如果消息时间戳不是最新的,可能不需要处理,或者记录一个警告 + pass + # logger.warning(f"[私聊][{self.private_name}]收到过时或无效时间戳的消息: ID={message_id}, time={message_time}") + + def update_changed(self): + """标记状态已改变,并重置标记""" + # logger.debug(f"[私聊][{self.private_name}]状态标记为已改变 (changed=True)") + self.changed = True + + async def update_cold_chat_status(self, is_cold: bool, current_time: float): + """更新冷场状态 + + Args: + is_cold: 是否处于冷场状态 + current_time: 当前时间戳 + """ + if is_cold != self.is_cold_chat: # 仅在状态变化时更新 + self.is_cold_chat = is_cold + if is_cold: + # 进入冷场状态 + self.cold_chat_start_time = ( + self.last_message_time or current_time + ) # 从最后消息时间开始算,或从当前时间开始 + logger.info(f"[私聊][{self.private_name}]进入冷场状态,开始时间: {self.cold_chat_start_time}") + else: + # 结束冷场状态 + if self.cold_chat_start_time: + self.cold_chat_duration = current_time - self.cold_chat_start_time + logger.info(f"[私聊][{self.private_name}]结束冷场状态,持续时间: {self.cold_chat_duration:.2f} 秒") + self.cold_chat_start_time = None # 重置开始时间 + self.update_changed() # 状态变化,标记改变 + + # 即使状态没变,如果是冷场状态,也更新持续时间 + if self.is_cold_chat and self.cold_chat_start_time: + self.cold_chat_duration = current_time - self.cold_chat_start_time + + def get_active_duration(self) -> float: + """获取当前活跃时长 (距离最后一条消息的时间) + + Returns: + float: 最后一条消息到现在的时长(秒) + """ + if not self.last_message_time: + return 0.0 + return time.time() - self.last_message_time + + def get_user_response_time(self) -> Optional[float]: + """获取用户最后响应时间 (距离用户最后发言的时间) + + Returns: + Optional[float]: 用户最后发言到现在的时长(秒),如果没有用户发言则返回None + """ + if not self.last_user_speak_time: + return None + return time.time() - self.last_user_speak_time + + def get_bot_response_time(self) -> Optional[float]: + """获取机器人最后响应时间 (距离机器人最后发言的时间) + + Returns: + Optional[float]: 机器人最后发言到现在的时长(秒),如果没有机器人发言则返回None + """ + if not self.last_bot_speak_time: + return None + return time.time() - self.last_bot_speak_time + + async def clear_unprocessed_messages(self): + """将未处理消息移入历史记录,并更新相关状态""" + if not self.unprocessed_messages: + return # 没有未处理消息,直接返回 + + # logger.debug(f"[私聊][{self.private_name}]处理 {len(self.unprocessed_messages)} 条未处理消息...") + # 将未处理消息添加到历史记录中 (确保历史记录有长度限制,避免无限增长) + max_history_len = 100 # 示例:最多保留100条历史记录 + self.chat_history.extend(self.unprocessed_messages) + if len(self.chat_history) > max_history_len: + self.chat_history = self.chat_history[-max_history_len:] + + # 更新历史记录字符串 (只使用最近一部分生成,例如20条) + history_slice_for_str = self.chat_history[-20:] + try: + self.chat_history_str = await build_readable_messages( + history_slice_for_str, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, # read_mark 可能需要根据逻辑调整 + ) + except Exception as e: + logger.error(f"[私聊][{self.private_name}]构建聊天记录字符串时出错: {e}") + self.chat_history_str = "[构建聊天记录出错]" # 提供错误提示 + + # 清空未处理消息列表和计数 + # cleared_count = len(self.unprocessed_messages) + self.unprocessed_messages.clear() + self.new_messages_count = 0 + # self.has_unread_messages = False # 这个状态可以通过 new_messages_count 判断 + + self.chat_history_count = len(self.chat_history) # 更新历史记录总数 + # logger.debug(f"[私聊][{self.private_name}]已处理 {cleared_count} 条消息,当前历史记录 {self.chat_history_count} 条。") + + self.update_changed() # 状态改变 diff --git a/src/chat/brain_chat/PFC/pfc.py b/src/chat/brain_chat/PFC/pfc.py new file mode 100644 index 00000000..b17ee21d --- /dev/null +++ b/src/chat/brain_chat/PFC/pfc.py @@ -0,0 +1,345 @@ +from typing import List, Tuple, TYPE_CHECKING +from src.common.logger import get_module_logger +from ..models.utils_model import LLMRequest +from ...config.config import global_config +from .chat_observer import ChatObserver +from .pfc_utils import get_items_from_json +from src.individuality.individuality import Individuality +from .conversation_info import ConversationInfo +from .observation_info import ObservationInfo +from src.plugins.utils.chat_message_builder import build_readable_messages +from rich.traceback import install + +install(extra_lines=3) + +if TYPE_CHECKING: + pass + +logger = get_module_logger("pfc") + + +def _calculate_similarity(goal1: str, goal2: str) -> float: + """简单计算两个目标之间的相似度 + + 这里使用一个简单的实现,实际可以使用更复杂的文本相似度算法 + + Args: + goal1: 第一个目标 + goal2: 第二个目标 + + Returns: + float: 相似度得分 (0-1) + """ + # 简单实现:检查重叠字数比例 + words1 = set(goal1) + words2 = set(goal2) + overlap = len(words1.intersection(words2)) + total = len(words1.union(words2)) + return overlap / total if total > 0 else 0 + + +class GoalAnalyzer: + """对话目标分析器""" + + def __init__(self, stream_id: str, private_name: str): + self.llm = LLMRequest( + model=global_config.llm_normal, temperature=0.7, max_tokens=1000, request_type="conversation_goal" + ) + + self.personality_info = Individuality.get_instance().get_prompt(x_person=2, level=3) + self.name = global_config.BOT_NICKNAME + self.nick_name = global_config.BOT_ALIAS_NAMES + self.private_name = private_name + self.chat_observer = ChatObserver.get_instance(stream_id, private_name) + + # 多目标存储结构 + self.goals = [] # 存储多个目标 + self.max_goals = 3 # 同时保持的最大目标数量 + self.current_goal_and_reason = None + + async def analyze_goal(self, conversation_info: ConversationInfo, observation_info: ObservationInfo): + """分析对话历史并设定目标 + + Args: + conversation_info: 对话信息 + observation_info: 观察信息 + + Returns: + Tuple[str, str, str]: (目标, 方法, 原因) + """ + # 构建对话目标 + goals_str = "" + if conversation_info.goal_list: + for goal_reason in conversation_info.goal_list: + if isinstance(goal_reason, dict): + goal = goal_reason.get("goal", "目标内容缺失") + reasoning = goal_reason.get("reasoning", "没有明确原因") + else: + goal = str(goal_reason) + reasoning = "没有明确原因" + + goal_str = f"目标:{goal},产生该对话目标的原因:{reasoning}\n" + goals_str += goal_str + else: + goal = "目前没有明确对话目标" + reasoning = "目前没有明确对话目标,最好思考一个对话目标" + goals_str = f"目标:{goal},产生该对话目标的原因:{reasoning}\n" + + # 获取聊天历史记录 + chat_history_text = observation_info.chat_history_str + + if observation_info.new_messages_count > 0: + new_messages_list = observation_info.unprocessed_messages + new_messages_str = await build_readable_messages( + new_messages_list, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + chat_history_text += f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" + + # await observation_info.clear_unprocessed_messages() + + persona_text = f"你的名字是{self.name},{self.personality_info}。" + # 构建action历史文本 + action_history_list = conversation_info.done_action + action_history_text = "你之前做的事情是:" + for action in action_history_list: + action_history_text += f"{action}\n" + + prompt = f"""{persona_text}。现在你在参与一场QQ聊天,请分析以下聊天记录,并根据你的性格特征确定多个明确的对话目标。 +这些目标应该反映出对话的不同方面和意图。 + +{action_history_text} +当前对话目标: +{goals_str} + +聊天记录: +{chat_history_text} + +请分析当前对话并确定最适合的对话目标。你可以: +1. 保持现有目标不变 +2. 修改现有目标 +3. 添加新目标 +4. 删除不再相关的目标 +5. 如果你想结束对话,请设置一个目标,目标goal为"结束对话",原因reasoning为你希望结束对话 + +请以JSON数组格式输出当前的所有对话目标,每个目标包含以下字段: +1. goal: 对话目标(简短的一句话) +2. reasoning: 对话原因,为什么设定这个目标(简要解释) + +输出格式示例: +[ +{{ + "goal": "回答用户关于Python编程的具体问题", + "reasoning": "用户提出了关于Python的技术问题,需要专业且准确的解答" +}}, +{{ + "goal": "回答用户关于python安装的具体问题", + "reasoning": "用户提出了关于Python的技术问题,需要专业且准确的解答" +}} +]""" + + logger.debug(f"[私聊][{self.private_name}]发送到LLM的提示词: {prompt}") + try: + content, _ = await self.llm.generate_response_async(prompt) + logger.debug(f"[私聊][{self.private_name}]LLM原始返回内容: {content}") + except Exception as e: + logger.error(f"[私聊][{self.private_name}]分析对话目标时出错: {str(e)}") + content = "" + + # 使用改进后的get_items_from_json函数处理JSON数组 + success, result = get_items_from_json( + content, + self.private_name, + "goal", + "reasoning", + required_types={"goal": str, "reasoning": str}, + allow_array=True, + ) + + if success: + # 判断结果是单个字典还是字典列表 + if isinstance(result, list): + # 清空现有目标列表并添加新目标 + conversation_info.goal_list = [] + for item in result: + conversation_info.goal_list.append(item) + + # 返回第一个目标作为当前主要目标(如果有) + if result: + first_goal = result[0] + return first_goal.get("goal", ""), "", first_goal.get("reasoning", "") + else: + # 单个目标的情况 + conversation_info.goal_list.append(result) + return goal, "", reasoning + + # 如果解析失败,返回默认值 + return "", "", "" + + async def _update_goals(self, new_goal: str, method: str, reasoning: str): + """更新目标列表 + + Args: + new_goal: 新的目标 + method: 实现目标的方法 + reasoning: 目标的原因 + """ + # 检查新目标是否与现有目标相似 + for i, (existing_goal, _, _) in enumerate(self.goals): + if _calculate_similarity(new_goal, existing_goal) > 0.7: # 相似度阈值 + # 更新现有目标 + self.goals[i] = (new_goal, method, reasoning) + # 将此目标移到列表前面(最主要的位置) + self.goals.insert(0, self.goals.pop(i)) + return + + # 添加新目标到列表前面 + self.goals.insert(0, (new_goal, method, reasoning)) + + # 限制目标数量 + if len(self.goals) > self.max_goals: + self.goals.pop() # 移除最老的目标 + + async def get_all_goals(self) -> List[Tuple[str, str, str]]: + """获取所有当前目标 + + Returns: + List[Tuple[str, str, str]]: 目标列表,每项为(目标, 方法, 原因) + """ + return self.goals.copy() + + async def get_alternative_goals(self) -> List[Tuple[str, str, str]]: + """获取除了当前主要目标外的其他备选目标 + + Returns: + List[Tuple[str, str, str]]: 备选目标列表 + """ + if len(self.goals) <= 1: + return [] + return self.goals[1:].copy() + + async def analyze_conversation(self, goal, reasoning): + messages = self.chat_observer.get_cached_messages() + chat_history_text = await build_readable_messages( + messages, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + + persona_text = f"你的名字是{self.name},{self.personality_info}。" + # ===> Persona 文本构建结束 <=== + + # --- 修改 Prompt 字符串,使用 persona_text --- + prompt = f"""{persona_text}。现在你在参与一场QQ聊天, + 当前对话目标:{goal} + 产生该对话目标的原因:{reasoning} + + 请分析以下聊天记录,并根据你的性格特征评估该目标是否已经达到,或者你是否希望停止该次对话。 + 聊天记录: + {chat_history_text} + 请以JSON格式输出,包含以下字段: + 1. goal_achieved: 对话目标是否已经达到(true/false) + 2. stop_conversation: 是否希望停止该次对话(true/false) + 3. reason: 为什么希望停止该次对话(简要解释) + +输出格式示例: +{{ + "goal_achieved": true, + "stop_conversation": false, + "reason": "虽然目标已达成,但对话仍然有继续的价值" +}}""" + + try: + content, _ = await self.llm.generate_response_async(prompt) + logger.debug(f"[私聊][{self.private_name}]LLM原始返回内容: {content}") + + # 尝试解析JSON + success, result = get_items_from_json( + content, + self.private_name, + "goal_achieved", + "stop_conversation", + "reason", + required_types={"goal_achieved": bool, "stop_conversation": bool, "reason": str}, + ) + + if not success: + logger.error(f"[私聊][{self.private_name}]无法解析对话分析结果JSON") + return False, False, "解析结果失败" + + goal_achieved = result["goal_achieved"] + stop_conversation = result["stop_conversation"] + reason = result["reason"] + + return goal_achieved, stop_conversation, reason + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]分析对话状态时出错: {str(e)}") + return False, False, f"分析出错: {str(e)}" + + +# 先注释掉,万一以后出问题了还能开回来((( +# class DirectMessageSender: +# """直接发送消息到平台的发送器""" + +# def __init__(self, private_name: str): +# self.logger = get_module_logger("direct_sender") +# self.storage = MessageStorage() +# self.private_name = private_name + +# async def send_via_ws(self, message: MessageSending) -> None: +# try: +# await global_api.send_message(message) +# except Exception as e: +# raise ValueError(f"未找到平台:{message.message_info.platform} 的url配置,请检查配置文件") from e + +# async def send_message( +# self, +# chat_stream: ChatStream, +# content: str, +# reply_to_message: Optional[Message] = None, +# ) -> None: +# """直接发送消息到平台 + +# Args: +# chat_stream: 聊天流 +# content: 消息内容 +# reply_to_message: 要回复的消息 +# """ +# # 构建消息对象 +# message_segment = Seg(type="text", data=content) +# bot_user_info = UserInfo( +# user_id=global_config.BOT_QQ, +# user_nickname=global_config.BOT_NICKNAME, +# platform=chat_stream.platform, +# ) + +# message = MessageSending( +# message_id=f"dm{round(time.time(), 2)}", +# chat_stream=chat_stream, +# bot_user_info=bot_user_info, +# sender_info=reply_to_message.message_info.user_info if reply_to_message else None, +# message_segment=message_segment, +# reply=reply_to_message, +# is_head=True, +# is_emoji=False, +# thinking_start_time=time.time(), +# ) + +# # 处理消息 +# await message.process() + +# _message_json = message.to_dict() + +# # 发送消息 +# try: +# await self.send_via_ws(message) +# await self.storage.store_message(message, chat_stream) +# logger.success(f"[私聊][{self.private_name}]PFC消息已发送: {content}") +# except Exception as e: +# logger.error(f"[私聊][{self.private_name}]PFC消息发送失败: {str(e)}") diff --git a/src/chat/brain_chat/PFC/pfc_KnowledgeFetcher.py b/src/chat/brain_chat/PFC/pfc_KnowledgeFetcher.py new file mode 100644 index 00000000..0989339d --- /dev/null +++ b/src/chat/brain_chat/PFC/pfc_KnowledgeFetcher.py @@ -0,0 +1,85 @@ +from typing import List, Tuple +from src.common.logger import get_module_logger +from src.plugins.memory_system.Hippocampus import HippocampusManager +from ..models.utils_model import LLMRequest +from ...config.config import global_config +from ..chat.message import Message +from ..knowledge.knowledge_lib import qa_manager +from ..utils.chat_message_builder import build_readable_messages + +logger = get_module_logger("knowledge_fetcher") + + +class KnowledgeFetcher: + """知识调取器""" + + def __init__(self, private_name: str): + self.llm = LLMRequest( + model=global_config.llm_normal, + temperature=global_config.llm_normal["temp"], + max_tokens=1000, + request_type="knowledge_fetch", + ) + self.private_name = private_name + + def _lpmm_get_knowledge(self, query: str) -> str: + """获取相关知识 + + Args: + query: 查询内容 + + Returns: + str: 构造好的,带相关度的知识 + """ + + logger.debug(f"[私聊][{self.private_name}]正在从LPMM知识库中获取知识") + try: + knowledge_info = qa_manager.get_knowledge(query) + logger.debug(f"[私聊][{self.private_name}]LPMM知识库查询结果: {knowledge_info:150}") + return knowledge_info + except Exception as e: + logger.error(f"[私聊][{self.private_name}]LPMM知识库搜索工具执行失败: {str(e)}") + return "未找到匹配的知识" + + async def fetch(self, query: str, chat_history: List[Message]) -> Tuple[str, str]: + """获取相关知识 + + Args: + query: 查询内容 + chat_history: 聊天历史 + + Returns: + Tuple[str, str]: (获取的知识, 知识来源) + """ + # 构建查询上下文 + chat_history_text = await build_readable_messages( + chat_history, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + + # 从记忆中获取相关知识 + related_memory = await HippocampusManager.get_instance().get_memory_from_text( + text=f"{query}\n{chat_history_text}", + max_memory_num=3, + max_memory_length=2, + max_depth=3, + fast_retrieval=False, + ) + knowledge_text = "" + sources_text = "无记忆匹配" # 默认值 + if related_memory: + sources = [] + for memory in related_memory: + knowledge_text += memory[1] + "\n" + sources.append(f"记忆片段{memory[0]}") + knowledge_text = knowledge_text.strip() + sources_text = ",".join(sources) + + knowledge_text += "\n现在有以下**知识**可供参考:\n " + knowledge_text += self._lpmm_get_knowledge(query) + knowledge_text += "\n请记住这些**知识**,并根据**知识**回答问题。\n" + + return knowledge_text or "未找到相关知识", sources_text or "无记忆匹配" diff --git a/src/chat/brain_chat/PFC/pfc_manager.py b/src/chat/brain_chat/PFC/pfc_manager.py new file mode 100644 index 00000000..7837606c --- /dev/null +++ b/src/chat/brain_chat/PFC/pfc_manager.py @@ -0,0 +1,115 @@ +import time +from typing import Dict, Optional +from src.common.logger import get_module_logger +from .conversation import Conversation +import traceback + +logger = get_module_logger("pfc_manager") + + +class PFCManager: + """PFC对话管理器,负责管理所有对话实例""" + + # 单例模式 + _instance = None + + # 会话实例管理 + _instances: Dict[str, Conversation] = {} + _initializing: Dict[str, bool] = {} + + @classmethod + def get_instance(cls) -> "PFCManager": + """获取管理器单例 + + Returns: + PFCManager: 管理器实例 + """ + if cls._instance is None: + cls._instance = PFCManager() + return cls._instance + + async def get_or_create_conversation(self, stream_id: str, private_name: str) -> Optional[Conversation]: + """获取或创建对话实例 + + Args: + stream_id: 聊天流ID + private_name: 私聊名称 + + Returns: + Optional[Conversation]: 对话实例,创建失败则返回None + """ + # 检查是否已经有实例 + if stream_id in self._initializing and self._initializing[stream_id]: + logger.debug(f"[私聊][{private_name}]会话实例正在初始化中: {stream_id}") + return None + + if stream_id in self._instances and self._instances[stream_id].should_continue: + logger.debug(f"[私聊][{private_name}]使用现有会话实例: {stream_id}") + return self._instances[stream_id] + if stream_id in self._instances: + instance = self._instances[stream_id] + if ( + hasattr(instance, "ignore_until_timestamp") + and instance.ignore_until_timestamp + and time.time() < instance.ignore_until_timestamp + ): + logger.debug(f"[私聊][{private_name}]会话实例当前处于忽略状态: {stream_id}") + # 返回 None 阻止交互。或者可以返回实例但标记它被忽略了喵? + # 还是返回 None 吧喵。 + return None + + # 检查 should_continue 状态 + if instance.should_continue: + logger.debug(f"[私聊][{private_name}]使用现有会话实例: {stream_id}") + return instance + # else: 实例存在但不应继续 + try: + # 创建新实例 + logger.info(f"[私聊][{private_name}]创建新的对话实例: {stream_id}") + self._initializing[stream_id] = True + # 创建实例 + conversation_instance = Conversation(stream_id, private_name) + self._instances[stream_id] = conversation_instance + + # 启动实例初始化 + await self._initialize_conversation(conversation_instance) + except Exception as e: + logger.error(f"[私聊][{private_name}]创建会话实例失败: {stream_id}, 错误: {e}") + return None + + return conversation_instance + + async def _initialize_conversation(self, conversation: Conversation): + """初始化会话实例 + + Args: + conversation: 要初始化的会话实例 + """ + stream_id = conversation.stream_id + private_name = conversation.private_name + + try: + logger.info(f"[私聊][{private_name}]开始初始化会话实例: {stream_id}") + # 启动初始化流程 + await conversation._initialize() + + # 标记初始化完成 + self._initializing[stream_id] = False + + logger.info(f"[私聊][{private_name}]会话实例 {stream_id} 初始化完成") + + except Exception as e: + logger.error(f"[私聊][{private_name}]管理器初始化会话实例失败: {stream_id}, 错误: {e}") + logger.error(f"[私聊][{private_name}]{traceback.format_exc()}") + # 清理失败的初始化 + + async def get_conversation(self, stream_id: str) -> Optional[Conversation]: + """获取已存在的会话实例 + + Args: + stream_id: 聊天流ID + + Returns: + Optional[Conversation]: 会话实例,不存在则返回None + """ + return self._instances.get(stream_id) diff --git a/src/chat/brain_chat/PFC/pfc_types.py b/src/chat/brain_chat/PFC/pfc_types.py new file mode 100644 index 00000000..0ea5eda6 --- /dev/null +++ b/src/chat/brain_chat/PFC/pfc_types.py @@ -0,0 +1,23 @@ +from enum import Enum +from typing import Literal + + +class ConversationState(Enum): + """对话状态""" + + INIT = "初始化" + RETHINKING = "重新思考" + ANALYZING = "分析历史" + PLANNING = "规划目标" + GENERATING = "生成回复" + CHECKING = "检查回复" + SENDING = "发送消息" + FETCHING = "获取知识" + WAITING = "等待" + LISTENING = "倾听" + ENDED = "结束" + JUDGING = "判断" + IGNORED = "屏蔽" + + +ActionType = Literal["direct_reply", "fetch_knowledge", "wait"] diff --git a/src/chat/brain_chat/PFC/pfc_utils.py b/src/chat/brain_chat/PFC/pfc_utils.py new file mode 100644 index 00000000..2f7bd5e0 --- /dev/null +++ b/src/chat/brain_chat/PFC/pfc_utils.py @@ -0,0 +1,127 @@ +import json +import re +from typing import Dict, Any, Optional, Tuple, List, Union +from src.common.logger import get_module_logger + +logger = get_module_logger("pfc_utils") + + +def get_items_from_json( + content: str, + private_name: str, + *items: str, + default_values: Optional[Dict[str, Any]] = None, + required_types: Optional[Dict[str, type]] = None, + allow_array: bool = True, +) -> Tuple[bool, Union[Dict[str, Any], List[Dict[str, Any]]]]: + """从文本中提取JSON内容并获取指定字段 + + Args: + content: 包含JSON的文本 + private_name: 私聊名称 + *items: 要提取的字段名 + default_values: 字段的默认值,格式为 {字段名: 默认值} + required_types: 字段的必需类型,格式为 {字段名: 类型} + allow_array: 是否允许解析JSON数组 + + Returns: + Tuple[bool, Union[Dict[str, Any], List[Dict[str, Any]]]]: (是否成功, 提取的字段字典或字典列表) + """ + content = content.strip() + result = {} + + # 设置默认值 + if default_values: + result.update(default_values) + + # 首先尝试解析为JSON数组 + if allow_array: + try: + # 尝试找到文本中的JSON数组 + array_pattern = r"\[[\s\S]*\]" + array_match = re.search(array_pattern, content) + if array_match: + array_content = array_match.group() + json_array = json.loads(array_content) + + # 确认是数组类型 + if isinstance(json_array, list): + # 验证数组中的每个项目是否包含所有必需字段 + valid_items = [] + for item in json_array: + if not isinstance(item, dict): + continue + + # 检查是否有所有必需字段 + if all(field in item for field in items): + # 验证字段类型 + if required_types: + type_valid = True + for field, expected_type in required_types.items(): + if field in item and not isinstance(item[field], expected_type): + type_valid = False + break + + if not type_valid: + continue + + # 验证字符串字段不为空 + string_valid = True + for field in items: + if isinstance(item[field], str) and not item[field].strip(): + string_valid = False + break + + if not string_valid: + continue + + valid_items.append(item) + + if valid_items: + return True, valid_items + except json.JSONDecodeError: + logger.debug(f"[私聊][{private_name}]JSON数组解析失败,尝试解析单个JSON对象") + except Exception as e: + logger.debug(f"[私聊][{private_name}]尝试解析JSON数组时出错: {str(e)}") + + # 尝试解析JSON对象 + try: + json_data = json.loads(content) + except json.JSONDecodeError: + # 如果直接解析失败,尝试查找和提取JSON部分 + json_pattern = r"\{[^{}]*\}" + json_match = re.search(json_pattern, content) + if json_match: + try: + json_data = json.loads(json_match.group()) + except json.JSONDecodeError: + logger.error(f"[私聊][{private_name}]提取的JSON内容解析失败") + return False, result + else: + logger.error(f"[私聊][{private_name}]无法在返回内容中找到有效的JSON") + return False, result + + # 提取字段 + for item in items: + if item in json_data: + result[item] = json_data[item] + + # 验证必需字段 + if not all(item in result for item in items): + logger.error(f"[私聊][{private_name}]JSON缺少必要字段,实际内容: {json_data}") + return False, result + + # 验证字段类型 + if required_types: + for field, expected_type in required_types.items(): + if field in result and not isinstance(result[field], expected_type): + logger.error(f"[私聊][{private_name}]{field} 必须是 {expected_type.__name__} 类型") + return False, result + + # 验证字符串字段不为空 + for field in items: + if isinstance(result[field], str) and not result[field].strip(): + logger.error(f"[私聊][{private_name}]{field} 不能为空") + return False, result + + return True, result diff --git a/src/chat/brain_chat/PFC/reply_checker.py b/src/chat/brain_chat/PFC/reply_checker.py new file mode 100644 index 00000000..35e9af50 --- /dev/null +++ b/src/chat/brain_chat/PFC/reply_checker.py @@ -0,0 +1,183 @@ +import json +from typing import Tuple, List, Dict, Any +from src.common.logger import get_module_logger +from ..models.utils_model import LLMRequest +from ...config.config import global_config +from .chat_observer import ChatObserver +from maim_message import UserInfo + +logger = get_module_logger("reply_checker") + + +class ReplyChecker: + """回复检查器""" + + def __init__(self, stream_id: str, private_name: str): + self.llm = LLMRequest( + model=global_config.llm_PFC_reply_checker, temperature=0.50, max_tokens=1000, request_type="reply_check" + ) + self.name = global_config.BOT_NICKNAME + self.private_name = private_name + self.chat_observer = ChatObserver.get_instance(stream_id, private_name) + self.max_retries = 3 # 最大重试次数 + + async def check( + self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_text: str, retry_count: int = 0 + ) -> Tuple[bool, str, bool]: + """检查生成的回复是否合适 + + Args: + reply: 生成的回复 + goal: 对话目标 + chat_history: 对话历史记录 + chat_history_text: 对话历史记录文本 + retry_count: 当前重试次数 + + Returns: + Tuple[bool, str, bool]: (是否合适, 原因, 是否需要重新规划) + """ + # 不再从 observer 获取,直接使用传入的 chat_history + # messages = self.chat_observer.get_cached_messages(limit=20) + try: + # 筛选出最近由 Bot 自己发送的消息 + bot_messages = [] + for msg in reversed(chat_history): + user_info = UserInfo.from_dict(msg.get("user_info", {})) + if str(user_info.user_id) == str(global_config.BOT_QQ): # 确保比较的是字符串 + bot_messages.append(msg.get("processed_plain_text", "")) + if len(bot_messages) >= 2: # 只和最近的两条比较 + break + # 进行比较 + if bot_messages: + # 可以用简单比较,或者更复杂的相似度库 (如 difflib) + # 简单比较:是否完全相同 + if reply == bot_messages[0]: # 和最近一条完全一样 + logger.warning( + f"[私聊][{self.private_name}]ReplyChecker 检测到回复与上一条 Bot 消息完全相同: '{reply}'" + ) + return ( + False, + "被逻辑检查拒绝:回复内容与你上一条发言完全相同,可以选择深入话题或寻找其它话题或等待", + True, + ) # 不合适,需要返回至决策层 + # 2. 相似度检查 (如果精确匹配未通过) + import difflib # 导入 difflib 库 + + # 计算编辑距离相似度,ratio() 返回 0 到 1 之间的浮点数 + similarity_ratio = difflib.SequenceMatcher(None, reply, bot_messages[0]).ratio() + logger.debug(f"[私聊][{self.private_name}]ReplyChecker - 相似度: {similarity_ratio:.2f}") + + # 设置一个相似度阈值 + similarity_threshold = 0.9 + if similarity_ratio > similarity_threshold: + logger.warning( + f"[私聊][{self.private_name}]ReplyChecker 检测到回复与上一条 Bot 消息高度相似 (相似度 {similarity_ratio:.2f}): '{reply}'" + ) + return ( + False, + f"被逻辑检查拒绝:回复内容与你上一条发言高度相似 (相似度 {similarity_ratio:.2f}),可以选择深入话题或寻找其它话题或等待。", + True, + ) + + except Exception as e: + import traceback + + logger.error(f"[私聊][{self.private_name}]检查回复时出错: 类型={type(e)}, 值={e}") + logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") # 打印详细的回溯信息 + + prompt = f"""你是一个聊天逻辑检查器,请检查以下回复或消息是否合适: + +当前对话目标:{goal} +最新的对话记录: +{chat_history_text} + +待检查的消息: +{reply} + +请结合聊天记录检查以下几点: +1. 这条消息是否依然符合当前对话目标和实现方式 +2. 这条消息是否与最新的对话记录保持一致性 +3. 是否存在重复发言,或重复表达同质内容(尤其是只是换一种方式表达了相同的含义) +4. 这条消息是否包含违规内容(例如血腥暴力,政治敏感等) +5. 这条消息是否以发送者的角度发言(不要让发送者自己回复自己的消息) +6. 这条消息是否通俗易懂 +7. 这条消息是否有些多余,例如在对方没有回复的情况下,依然连续多次“消息轰炸”(尤其是已经连续发送3条信息的情况,这很可能不合理,需要着重判断) +8. 这条消息是否使用了完全没必要的修辞 +9. 这条消息是否逻辑通顺 +10. 这条消息是否太过冗长了(通常私聊的每条消息长度在20字以内,除非特殊情况) +11. 在连续多次发送消息的情况下,这条消息是否衔接自然,会不会显得奇怪(例如连续两条消息中部分内容重叠) + +请以JSON格式输出,包含以下字段: +1. suitable: 是否合适 (true/false) +2. reason: 原因说明 +3. need_replan: 是否需要重新决策 (true/false),当你认为此时已经不适合发消息,需要规划其它行动时,设为true + +输出格式示例: +{{ + "suitable": true, + "reason": "回复符合要求,虽然有可能略微偏离目标,但是整体内容流畅得体", + "need_replan": false +}} + +注意:请严格按照JSON格式输出,不要包含任何其他内容。""" + + try: + content, _ = await self.llm.generate_response_async(prompt) + logger.debug(f"[私聊][{self.private_name}]检查回复的原始返回: {content}") + + # 清理内容,尝试提取JSON部分 + content = content.strip() + try: + # 尝试直接解析 + result = json.loads(content) + except json.JSONDecodeError: + # 如果直接解析失败,尝试查找和提取JSON部分 + import re + + json_pattern = r"\{[^{}]*\}" + json_match = re.search(json_pattern, content) + if json_match: + try: + result = json.loads(json_match.group()) + except json.JSONDecodeError: + # 如果JSON解析失败,尝试从文本中提取结果 + is_suitable = "不合适" not in content.lower() and "违规" not in content.lower() + reason = content[:100] if content else "无法解析响应" + need_replan = "重新规划" in content.lower() or "目标不适合" in content.lower() + return is_suitable, reason, need_replan + else: + # 如果找不到JSON,从文本中判断 + is_suitable = "不合适" not in content.lower() and "违规" not in content.lower() + reason = content[:100] if content else "无法解析响应" + need_replan = "重新规划" in content.lower() or "目标不适合" in content.lower() + return is_suitable, reason, need_replan + + # 验证JSON字段 + suitable = result.get("suitable", None) + reason = result.get("reason", "未提供原因") + need_replan = result.get("need_replan", False) + + # 如果suitable字段是字符串,转换为布尔值 + if isinstance(suitable, str): + suitable = suitable.lower() == "true" + + # 如果suitable字段不存在或不是布尔值,从reason中判断 + if suitable is None: + suitable = "不合适" not in reason.lower() and "违规" not in reason.lower() + + # 如果不合适且未达到最大重试次数,返回需要重试 + if not suitable and retry_count < self.max_retries: + return False, reason, False + + # 如果不合适且已达到最大重试次数,返回需要重新规划 + if not suitable and retry_count >= self.max_retries: + return False, f"多次重试后仍不合适: {reason}", True + + return suitable, reason, need_replan + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]检查回复时出错: {e}") + # 如果出错且已达到最大重试次数,建议重新规划 + if retry_count >= self.max_retries: + return False, "多次检查失败,建议重新规划", True + return False, f"检查过程出错,建议重试: {str(e)}", False diff --git a/src/chat/brain_chat/PFC/reply_generator.py b/src/chat/brain_chat/PFC/reply_generator.py new file mode 100644 index 00000000..890f807c --- /dev/null +++ b/src/chat/brain_chat/PFC/reply_generator.py @@ -0,0 +1,228 @@ +from typing import Tuple, List, Dict, Any +from src.common.logger import get_module_logger +from ..models.utils_model import LLMRequest +from ...config.config import global_config +from .chat_observer import ChatObserver +from .reply_checker import ReplyChecker +from src.individuality.individuality import Individuality +from .observation_info import ObservationInfo +from .conversation_info import ConversationInfo +from src.plugins.utils.chat_message_builder import build_readable_messages + +logger = get_module_logger("reply_generator") + +# --- 定义 Prompt 模板 --- + +# Prompt for direct_reply (首次回复) +PROMPT_DIRECT_REPLY = """{persona_text}。现在你在参与一场QQ私聊,请根据以下信息生成一条回复: + +当前对话目标:{goals_str} + +{knowledge_info_str} + +最近的聊天记录: +{chat_history_text} + + +请根据上述信息,结合聊天记录,回复对方。该回复应该: +1. 符合对话目标,以"你"的角度发言(不要自己与自己对话!) +2. 符合你的性格特征和身份细节 +3. 通俗易懂,自然流畅,像正常聊天一样,简短(通常20字以内,除非特殊情况) +4. 可以适当利用相关知识,但不要生硬引用 +5. 自然、得体,结合聊天记录逻辑合理,且没有重复表达同质内容 + +请注意把握聊天内容,不要回复的太有条理,可以有个性。请分清"你"和对方说的话,不要把"你"说的话当做对方说的话,这是你自己说的话。 +可以回复得自然随意自然一些,就像真人一样,注意把握聊天内容,整体风格可以平和、简短,不要刻意突出自身学科背景,不要说你说过的话,可以简短,多简短都可以,但是避免冗长。 +请你注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。 +不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。 + +请直接输出回复内容,不需要任何额外格式。""" + +# Prompt for send_new_message (追问/补充) +PROMPT_SEND_NEW_MESSAGE = """{persona_text}。现在你在参与一场QQ私聊,**刚刚你已经发送了一条或多条消息**,现在请根据以下信息再发一条新消息: + +当前对话目标:{goals_str} + +{knowledge_info_str} + +最近的聊天记录: +{chat_history_text} + + +请根据上述信息,结合聊天记录,继续发一条新消息(例如对之前消息的补充,深入话题,或追问等等)。该消息应该: +1. 符合对话目标,以"你"的角度发言(不要自己与自己对话!) +2. 符合你的性格特征和身份细节 +3. 通俗易懂,自然流畅,像正常聊天一样,简短(通常20字以内,除非特殊情况) +4. 可以适当利用相关知识,但不要生硬引用 +5. 跟之前你发的消息自然的衔接,逻辑合理,且没有重复表达同质内容或部分重叠内容 + +请注意把握聊天内容,不用太有条理,可以有个性。请分清"你"和对方说的话,不要把"你"说的话当做对方说的话,这是你自己说的话。 +这条消息可以自然随意自然一些,就像真人一样,注意把握聊天内容,整体风格可以平和、简短,不要刻意突出自身学科背景,不要说你说过的话,可以简短,多简短都可以,但是避免冗长。 +请你注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出消息内容。 +不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。 + +请直接输出回复内容,不需要任何额外格式。""" + +# Prompt for say_goodbye (告别语生成) +PROMPT_FAREWELL = """{persona_text}。你在参与一场 QQ 私聊,现在对话似乎已经结束,你决定再发一条最后的消息来圆满结束。 + +最近的聊天记录: +{chat_history_text} + +请根据上述信息,结合聊天记录,构思一条**简短、自然、符合你人设**的最后的消息。 +这条消息应该: +1. 从你自己的角度发言。 +2. 符合你的性格特征和身份细节。 +3. 通俗易懂,自然流畅,通常很简短。 +4. 自然地为这场对话画上句号,避免开启新话题或显得冗长、刻意。 + +请像真人一样随意自然,**简洁是关键**。 +不要输出多余内容(包括前后缀、冒号、引号、括号、表情包、at或@等)。 + +请直接输出最终的告别消息内容,不需要任何额外格式。""" + + +class ReplyGenerator: + """回复生成器""" + + def __init__(self, stream_id: str, private_name: str): + self.llm = LLMRequest( + model=global_config.llm_PFC_chat, + temperature=global_config.llm_PFC_chat["temp"], + max_tokens=300, + request_type="reply_generation", + ) + self.personality_info = Individuality.get_instance().get_prompt(x_person=2, level=3) + self.name = global_config.BOT_NICKNAME + self.private_name = private_name + self.chat_observer = ChatObserver.get_instance(stream_id, private_name) + self.reply_checker = ReplyChecker(stream_id, private_name) + + # 修改 generate 方法签名,增加 action_type 参数 + async def generate( + self, observation_info: ObservationInfo, conversation_info: ConversationInfo, action_type: str + ) -> str: + """生成回复 + + Args: + observation_info: 观察信息 + conversation_info: 对话信息 + action_type: 当前执行的动作类型 ('direct_reply' 或 'send_new_message') + + Returns: + str: 生成的回复 + """ + # 构建提示词 + logger.debug( + f"[私聊][{self.private_name}]开始生成回复 (动作类型: {action_type}):当前目标: {conversation_info.goal_list}" + ) + + # --- 构建通用 Prompt 参数 --- + # (这部分逻辑基本不变) + + # 构建对话目标 (goals_str) + goals_str = "" + if conversation_info.goal_list: + for goal_reason in conversation_info.goal_list: + if isinstance(goal_reason, dict): + goal = goal_reason.get("goal", "目标内容缺失") + reasoning = goal_reason.get("reasoning", "没有明确原因") + else: + goal = str(goal_reason) + reasoning = "没有明确原因" + + goal = str(goal) if goal is not None else "目标内容缺失" + reasoning = str(reasoning) if reasoning is not None else "没有明确原因" + goals_str += f"- 目标:{goal}\n 原因:{reasoning}\n" + else: + goals_str = "- 目前没有明确对话目标\n" # 简化无目标情况 + + # --- 新增:构建知识信息字符串 --- + knowledge_info_str = "【供参考的相关知识和记忆】\n" # 稍微改下标题,表明是供参考 + try: + # 检查 conversation_info 是否有 knowledge_list 并且不为空 + if hasattr(conversation_info, "knowledge_list") and conversation_info.knowledge_list: + # 最多只显示最近的 5 条知识 + recent_knowledge = conversation_info.knowledge_list[-5:] + for i, knowledge_item in enumerate(recent_knowledge): + if isinstance(knowledge_item, dict): + query = knowledge_item.get("query", "未知查询") + knowledge = knowledge_item.get("knowledge", "无知识内容") + source = knowledge_item.get("source", "未知来源") + # 只取知识内容的前 2000 个字 + knowledge_snippet = knowledge[:2000] + "..." if len(knowledge) > 2000 else knowledge + knowledge_info_str += ( + f"{i + 1}. 关于 '{query}' (来源: {source}): {knowledge_snippet}\n" # 格式微调,更简洁 + ) + else: + knowledge_info_str += f"{i + 1}. 发现一条格式不正确的知识记录。\n" + + if not recent_knowledge: + knowledge_info_str += "- 暂无。\n" # 更简洁的提示 + + else: + knowledge_info_str += "- 暂无。\n" + except AttributeError: + logger.warning(f"[私聊][{self.private_name}]ConversationInfo 对象可能缺少 knowledge_list 属性。") + knowledge_info_str += "- 获取知识列表时出错。\n" + except Exception as e: + logger.error(f"[私聊][{self.private_name}]构建知识信息字符串时出错: {e}") + knowledge_info_str += "- 处理知识列表时出错。\n" + + # 获取聊天历史记录 (chat_history_text) + chat_history_text = observation_info.chat_history_str + if observation_info.new_messages_count > 0 and observation_info.unprocessed_messages: + new_messages_list = observation_info.unprocessed_messages + new_messages_str = await build_readable_messages( + new_messages_list, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + chat_history_text += f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" + elif not chat_history_text: + chat_history_text = "还没有聊天记录。" + + # 构建 Persona 文本 (persona_text) + persona_text = f"你的名字是{self.name},{self.personality_info}。" + + # --- 选择 Prompt --- + if action_type == "send_new_message": + prompt_template = PROMPT_SEND_NEW_MESSAGE + logger.info(f"[私聊][{self.private_name}]使用 PROMPT_SEND_NEW_MESSAGE (追问生成)") + elif action_type == "say_goodbye": # 处理告别动作 + prompt_template = PROMPT_FAREWELL + logger.info(f"[私聊][{self.private_name}]使用 PROMPT_FAREWELL (告别语生成)") + else: # 默认使用 direct_reply 的 prompt (包括 'direct_reply' 或其他未明确处理的类型) + prompt_template = PROMPT_DIRECT_REPLY + logger.info(f"[私聊][{self.private_name}]使用 PROMPT_DIRECT_REPLY (首次/非连续回复生成)") + + # --- 格式化最终的 Prompt --- + prompt = prompt_template.format( + persona_text=persona_text, + goals_str=goals_str, + chat_history_text=chat_history_text, + knowledge_info_str=knowledge_info_str, + ) + + # --- 调用 LLM 生成 --- + logger.debug(f"[私聊][{self.private_name}]发送到LLM的生成提示词:\n------\n{prompt}\n------") + try: + content, _ = await self.llm.generate_response_async(prompt) + logger.debug(f"[私聊][{self.private_name}]生成的回复: {content}") + # 移除旧的检查新消息逻辑,这应该由 conversation 控制流处理 + return content + + except Exception as e: + logger.error(f"[私聊][{self.private_name}]生成回复时出错: {e}") + return "抱歉,我现在有点混乱,让我重新思考一下..." + + # check_reply 方法保持不变 + async def check_reply( + self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_str: str, retry_count: int = 0 + ) -> Tuple[bool, str, bool]: + """检查回复是否合适 + (此方法逻辑保持不变) + """ + return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, retry_count) diff --git a/src/chat/brain_chat/PFC/waiter.py b/src/chat/brain_chat/PFC/waiter.py new file mode 100644 index 00000000..0f5881fc --- /dev/null +++ b/src/chat/brain_chat/PFC/waiter.py @@ -0,0 +1,79 @@ +from src.common.logger import get_module_logger +from .chat_observer import ChatObserver +from .conversation_info import ConversationInfo + +# from src.individuality.individuality import Individuality # 不再需要 +from ...config.config import global_config +import time +import asyncio + +logger = get_module_logger("waiter") + +# --- 在这里设定你想要的超时时间(秒) --- +# 例如: 120 秒 = 2 分钟 +DESIRED_TIMEOUT_SECONDS = 300 + + +class Waiter: + """等待处理类""" + + def __init__(self, stream_id: str, private_name: str): + self.chat_observer = ChatObserver.get_instance(stream_id, private_name) + self.name = global_config.BOT_NICKNAME + self.private_name = private_name + # self.wait_accumulated_time = 0 # 不再需要累加计时 + + async def wait(self, conversation_info: ConversationInfo) -> bool: + """等待用户新消息或超时""" + wait_start_time = time.time() + logger.info(f"[私聊][{self.private_name}]进入常规等待状态 (超时: {DESIRED_TIMEOUT_SECONDS} 秒)...") + + while True: + # 检查是否有新消息 + if self.chat_observer.new_message_after(wait_start_time): + logger.info(f"[私聊][{self.private_name}]等待结束,收到新消息") + return False # 返回 False 表示不是超时 + + # 检查是否超时 + elapsed_time = time.time() - wait_start_time + if elapsed_time > DESIRED_TIMEOUT_SECONDS: + logger.info(f"[私聊][{self.private_name}]等待超过 {DESIRED_TIMEOUT_SECONDS} 秒...添加思考目标。") + wait_goal = { + "goal": f"你等待了{elapsed_time / 60:.1f}分钟,注意可能在对方看来聊天已经结束,思考接下来要做什么", + "reasoning": "对方很久没有回复你的消息了", + } + conversation_info.goal_list.append(wait_goal) + logger.info(f"[私聊][{self.private_name}]添加目标: {wait_goal}") + return True # 返回 True 表示超时 + + await asyncio.sleep(5) # 每 5 秒检查一次 + logger.debug( + f"[私聊][{self.private_name}]等待中..." + ) # 可以考虑把这个频繁日志注释掉,只在超时或收到消息时输出 + + async def wait_listening(self, conversation_info: ConversationInfo) -> bool: + """倾听用户发言或超时""" + wait_start_time = time.time() + logger.info(f"[私聊][{self.private_name}]进入倾听等待状态 (超时: {DESIRED_TIMEOUT_SECONDS} 秒)...") + + while True: + # 检查是否有新消息 + if self.chat_observer.new_message_after(wait_start_time): + logger.info(f"[私聊][{self.private_name}]倾听等待结束,收到新消息") + return False # 返回 False 表示不是超时 + + # 检查是否超时 + elapsed_time = time.time() - wait_start_time + if elapsed_time > DESIRED_TIMEOUT_SECONDS: + logger.info(f"[私聊][{self.private_name}]倾听等待超过 {DESIRED_TIMEOUT_SECONDS} 秒...添加思考目标。") + wait_goal = { + # 保持 goal 文本一致 + "goal": f"你等待了{elapsed_time / 60:.1f}分钟,对方似乎话说一半突然消失了,可能忙去了?也可能忘记了回复?要问问吗?还是结束对话?或继续等待?思考接下来要做什么", + "reasoning": "对方话说一半消失了,很久没有回复", + } + conversation_info.goal_list.append(wait_goal) + logger.info(f"[私聊][{self.private_name}]添加目标: {wait_goal}") + return True # 返回 True 表示超时 + + await asyncio.sleep(5) # 每 5 秒检查一次 + logger.debug(f"[私聊][{self.private_name}]倾听等待中...") # 同上,可以考虑注释掉 diff --git a/src/chat/brain_chat/brain_chat.py b/src/chat/brain_chat/brain_chat.py index 8702248f..9945b496 100644 --- a/src/chat/brain_chat/brain_chat.py +++ b/src/chat/brain_chat/brain_chat.py @@ -96,6 +96,9 @@ class BrainChatting: self.more_plan = False + # 最近一次是否成功进行了 reply,用于选择 BrainPlanner 的 Prompt + self._last_successful_reply: bool = False + async def start(self): """检查是否需要启动主循环,如果未激活则启动。""" @@ -157,6 +160,7 @@ class BrainChatting: ) async def _loopbody(self): # sourcery skip: hoist-if-from-if + # 获取最新消息(用于上下文,但不影响是否调用 observe) recent_messages_list = message_api.get_messages_by_time_in_chat( chat_id=self.stream_id, start_time=self.last_read_time, @@ -165,17 +169,25 @@ class BrainChatting: limit_mode="latest", filter_mai=True, filter_command=False, - filter_no_read_command=True, + filter_intercept_message_level=1, ) + # 如果有新消息,更新 last_read_time if len(recent_messages_list) >= 1: self.last_read_time = time.time() - await self._observe(recent_messages_list=recent_messages_list) - - else: - # Normal模式:消息数量不足,等待 - await asyncio.sleep(0.2) - return True + + # 总是执行一次思考迭代(不管有没有新消息) + # 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( @@ -272,14 +284,16 @@ class BrainChatting: except Exception as e: logger.error(f"{self.log_prefix} 动作修改失败: {e}") - # 执行planner + # 获取必要信息 is_group_chat, chat_target_info, _ = self.action_planner.get_necessary_info() + # 一次思考迭代:Think - Act - Observe + # 获取聊天上下文 message_list_before_now = get_raw_msg_before_timestamp_with_chat( chat_id=self.stream_id, timestamp=time.time(), limit=int(global_config.chat.max_context_size * 0.6), - filter_no_read_command=True, + filter_intercept_message_level=1, ) chat_content_block, message_id_list = build_readable_messages_with_id( messages=message_list_before_now, @@ -290,12 +304,12 @@ class BrainChatting: ) prompt_info = await self.action_planner.build_planner_prompt( - is_group_chat=is_group_chat, chat_target_info=chat_target_info, current_available_actions=available_actions, chat_content_block=chat_content_block, message_id_list=message_id_list, interest=global_config.personality.interest, + prompt_key="brain_planner_prompt_react", ) continue_flag, modified_message = await events_manager.handle_mai_events( EventType.ON_PLAN, None, prompt_info[0], None, self.chat_stream.stream_id @@ -311,7 +325,12 @@ class BrainChatting: available_actions=available_actions, ) - # 3. 并行执行所有动作 + # 检查是否有 complete_talk 动作(会停止后续迭代) + has_complete_talk = any( + action.action_type == "complete_talk" for action in action_to_use_info + ) + + # 并行执行所有动作 action_tasks = [ asyncio.create_task( self._execute_action(action, action_to_use_info, thinking_id, available_actions, cycle_timers) @@ -343,7 +362,14 @@ class BrainChatting: else: logger.warning(f"{self.log_prefix} 回复动作执行失败") - # 构建最终的循环信息 + # 更新观察时间标记 + self.action_planner.last_obs_time_mark = time.time() + + # 如果选择了 complete_talk,标记为完成,不再继续迭代 + if has_complete_talk: + logger.info(f"{self.log_prefix} 检测到 complete_talk 动作,本次思考完成") + + # 构建循环信息 if reply_loop_info: # 如果有回复信息,使用回复的loop_info作为基础 loop_info = reply_loop_info @@ -369,10 +395,16 @@ class BrainChatting: } _reply_text = action_reply_text + # 如果选择了 complete_talk,返回 False 以停止 _loopbody 的循环 + # 否则返回 True,让 _loopbody 继续下一次迭代 + should_continue = not has_complete_talk + self.end_cycle(loop_info, cycle_timers) self.print_cycle_info(cycle_timers) - return True + # 如果选择了 complete_talk,返回 False 停止循环 + # 否则返回 True,继续下一次思考迭代 + return should_continue async def _main_chat_loop(self): """主循环,持续进行计划并可能回复消息,直到被外部取消。""" @@ -380,9 +412,13 @@ class BrainChatting: while self.running: # 主循环 success = await self._loopbody() - await asyncio.sleep(0.1) if not success: - break + # 选择了 complete,等待新消息 + logger.info(f"{self.log_prefix} 选择了 complete,等待新消息...") + await self._wait_for_new_message() + # 有新消息后继续循环 + continue + await asyncio.sleep(0.1) except asyncio.CancelledError: # 设置了关闭标志位后被取消是正常流程 logger.info(f"{self.log_prefix} 麦麦已关闭聊天") @@ -392,6 +428,33 @@ 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( + chat_id=self.stream_id, + start_time=last_check_time, + end_time=time.time(), + limit=20, + limit_mode="latest", + filter_mai=True, + 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) async def _handle_action( self, @@ -506,12 +569,12 @@ class BrainChatting: """执行单个动作的通用函数""" try: with Timer(f"动作{action_planner_info.action_type}", cycle_timers): - if action_planner_info.action_type == "no_reply": - # 直接处理no_reply逻辑,不再通过动作系统 - reason = action_planner_info.reasoning or "选择不回复" - # logger.info(f"{self.log_prefix} 选择不回复,原因: {reason}") + if action_planner_info.action_type == "complete_talk": + # 直接处理complete_talk逻辑,不再通过动作系统 + reason = action_planner_info.reasoning or "选择完成对话" + logger.info(f"{self.log_prefix} 选择完成对话,原因: {reason}") - # 存储no_reply信息到数据库 + # 存储complete_talk信息到数据库 await database_api.store_action_info( chat_stream=self.chat_stream, action_build_into_prompt=False, @@ -519,9 +582,9 @@ class BrainChatting: action_done=True, thinking_id=thinking_id, action_data={"reason": reason}, - action_name="no_reply", + action_name="complete_talk", ) - return {"action_type": "no_reply", "success": True, "reply_text": "", "command": ""} + return {"action_type": "complete_talk", "success": True, "reply_text": "", "command": ""} elif action_planner_info.action_type == "reply": try: @@ -543,11 +606,17 @@ class BrainChatting: ) else: logger.info("回复生成失败") - return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None} + return { + "action_type": "reply", + "success": False, + "reply_text": "", + "loop_info": None, + } except asyncio.CancelledError: logger.debug(f"{self.log_prefix} 并行执行:回复生成任务已被取消") return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None} + response_set = llm_response.reply_set selected_expressions = llm_response.selected_expressions loop_info, reply_text, _ = await self._send_and_store_reply( @@ -558,6 +627,8 @@ class BrainChatting: actions=chosen_action_plan_infos, selected_expressions=selected_expressions, ) + # 标记这次循环已经成功进行了回复 + self._last_successful_reply = True return { "action_type": "reply", "success": True, @@ -567,7 +638,88 @@ class BrainChatting: # 其他动作 else: - # 执行普通动作 + # 内建 wait / listening:不通过插件系统,直接在这里处理 + if action_planner_info.action_type in ["wait", "listening"]: + reason = action_planner_info.reasoning or "" + action_data = action_planner_info.action_data or {} + + if action_planner_info.action_type == "wait": + # 获取等待时间(必填) + wait_seconds = action_data.get("wait_seconds") + if wait_seconds is None: + logger.warning(f"{self.log_prefix} wait 动作缺少 wait_seconds 参数,使用默认值 5 秒") + wait_seconds = 5 + else: + try: + wait_seconds = float(wait_seconds) + if wait_seconds < 0: + logger.warning(f"{self.log_prefix} wait_seconds 不能为负数,使用默认值 5 秒") + wait_seconds = 5 + 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, + action_build_into_prompt=False, + action_prompt_display=reason or f"等待 {wait_seconds} 秒", + action_done=True, + thinking_id=thinking_id, + 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 { + "action_type": "wait", + "success": True, + "reply_text": "", + "command": "", + } + + # listening 已合并到 wait,如果遇到则转换为 wait(向后兼容) + elif action_planner_info.action_type == "listening": + 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, + action_build_into_prompt=False, + action_prompt_display=reason or f"倾听并等待 {wait_seconds} 秒", + action_done=True, + thinking_id=thinking_id, + 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 { + "action_type": "listening", + "success": True, + "reply_text": "", + "command": "", + } + + # 其余动作:走原有插件 Action 体系 with Timer("动作执行", cycle_timers): success, reply_text, command = await self._handle_action( action_planner_info.action_type, @@ -577,6 +729,10 @@ class BrainChatting: thinking_id, action_planner_info.action_message, ) + # 非 reply 类动作执行成功时,清空最近成功回复标记,让下一轮回到 initial Prompt + if success and action_planner_info.action_type != "reply": + self._last_successful_reply = False + return { "action_type": action_planner_info.action_type, "success": success, diff --git a/src/chat/brain_chat/brain_planner.py b/src/chat/brain_chat/brain_planner.py index 739ff106..df143ead 100644 --- a/src/chat/brain_chat/brain_planner.py +++ b/src/chat/brain_chat/brain_planner.py @@ -35,12 +35,14 @@ install(extra_lines=3) def init_prompt(): + # ReAct 形式的 Planner Prompt Prompt( """ {time_block} {name_block} 你的兴趣是:{interest} {chat_context_description},以下是具体的聊天内容 + **聊天内容** {chat_content_block} @@ -57,11 +59,35 @@ reply "reason":"回复的原因" }} -no_reply +wait 动作描述: -等待,保持沉默,等待对方发言 +暂时不再发言,等待指定时间。适用于以下情况: +- 你已经表达清楚一轮,想给对方留出空间 +- 你感觉对方的话还没说完,或者自己刚刚发了好几条连续消息 +- 你想要等待一定时间来让对方把话说完,或者等待对方反应 +- 你想保持安静,专注"听"而不是马上回复 +请你根据上下文来判断要等待多久,请你灵活判断: +- 如果你们交流间隔时间很短,聊的很频繁,不宜等待太久 +- 如果你们交流间隔时间很长,聊的很少,可以等待较长时间 {{ - "action": "no_reply", + "action": "wait", + "target_message_id":"想要作为这次等待依据的消息id(通常是对方的最新消息)", + "wait_seconds": 等待的秒数(必填,例如:5 表示等待5秒), + "reason":"选择等待的原因" +}} + +complete_talk +动作描述: +当前聊天暂时结束了,对方离开,没有更多话题了 +你可以使用该动作来暂时休息,等待对方有新发言再继续: +- 多次wait之后,对方迟迟不回复消息才用 +- 如果对方只是短暂不回复,应该使用wait而不是complete_talk +- 聊天内容显示当前聊天已经结束或者没有新内容时候,选择complete_talk +选择此动作后,将不再继续循环思考,直到收到对方的新消息 +{{ + "action": "complete_talk", + "target_message_id":"触发完成对话的消息id(通常是对方的最新消息)", + "reason":"选择完成对话的原因" }} {action_options_text} @@ -92,7 +118,7 @@ no_reply ``` """, - "brain_planner_prompt", + "brain_planner_prompt_react", ) Prompt( @@ -122,6 +148,9 @@ class BrainPlanner: ) # 用于动作规划 self.last_obs_time_mark = 0.0 + + # 计划日志记录 + self.plan_log: List[Tuple[str, float, List[ActionPlannerInfo]]] = [] def find_message_by_id( self, message_id: str, message_id_list: List[Tuple[str, "DatabaseMessages"]] @@ -152,10 +181,11 @@ class BrainPlanner: action_planner_infos = [] try: - action = action_json.get("action", "no_reply") + action = action_json.get("action", "complete_talk") + logger.debug(f"{self.log_prefix}解析动作JSON: action={action}, json={action_json}") reasoning = action_json.get("reason", "未提供原因") action_data = {key: value for key, value in action_json.items() if key not in ["action", "reason"]} - # 非no_reply动作需要target_message_id + # 非complete_talk动作需要target_message_id target_message = None if target_message_id := action_json.get("target_message_id"): @@ -171,16 +201,26 @@ class BrainPlanner: # 验证action是否可用 available_action_names = [action_name for action_name, _ in current_available_actions] - internal_action_names = ["no_reply", "reply", "wait_time"] + # 内部保留动作(不依赖插件系统) + # 注意: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}") + + # 将 listening 转换为 wait(向后兼容) + if action == "listening": + logger.debug(f"{self.log_prefix}检测到 listening 动作,已合并到 wait,自动转换") + action = "wait" if action not in internal_action_names and action not in available_action_names: logger.warning( - f"{self.log_prefix}LLM 返回了当前不可用或无效的动作: '{action}' (可用: {available_action_names}),将强制使用 'no_reply'" + f"{self.log_prefix}LLM 返回了当前不可用或无效的动作: '{action}' (内部动作: {internal_action_names}, 可用插件动作: {available_action_names}),将强制使用 'complete_talk'" ) reasoning = ( f"LLM 返回了当前不可用的动作 '{action}' (可用: {available_action_names})。原始理由: {reasoning}" ) - action = "no_reply" + action = "complete_talk" + logger.warning(f"{self.log_prefix}动作已转换为 complete_talk") # 创建ActionPlannerInfo对象 # 将列表转换为字典格式 @@ -201,7 +241,7 @@ class BrainPlanner: available_actions_dict = dict(current_available_actions) action_planner_infos.append( ActionPlannerInfo( - action_type="no_reply", + action_type="complete_talk", reasoning=f"解析单个action时出错: {e}", action_data={}, action_message=None, @@ -218,7 +258,7 @@ class BrainPlanner: ) -> List[ActionPlannerInfo]: # sourcery skip: use-named-expression """ - 规划器 (Planner): 使用LLM根据上下文决定做出什么动作。 + 规划器 (Planner): 使用LLM根据上下文决定做出什么动作(ReAct模式)。 """ # 获取聊天上下文 @@ -226,7 +266,7 @@ class BrainPlanner: chat_id=self.chat_id, timestamp=time.time(), limit=int(global_config.chat.max_context_size * 0.6), - filter_no_read_command=True, + filter_intercept_message_level=1, ) message_id_list: list[Tuple[str, "DatabaseMessages"]] = [] chat_content_block, message_id_list = build_readable_messages_with_id( @@ -257,18 +297,20 @@ class BrainPlanner: logger.debug(f"{self.log_prefix}过滤后有{len(filtered_actions)}个可用动作") - # 构建包含所有动作的提示词 + # 构建包含所有动作的提示词:使用统一的 ReAct Prompt + prompt_key = "brain_planner_prompt_react" + # 这里不记录日志,避免重复打印,由调用方按需控制 log_prompt prompt, message_id_list = await self.build_planner_prompt( - is_group_chat=is_group_chat, chat_target_info=chat_target_info, current_available_actions=filtered_actions, chat_content_block=chat_content_block, message_id_list=message_id_list, interest=global_config.personality.interest, + prompt_key=prompt_key, ) # 调用LLM获取决策 - actions = await self._execute_main_planner( + reasoning, actions = await self._execute_main_planner( prompt=prompt, message_id_list=message_id_list, filtered_actions=filtered_actions, @@ -276,16 +318,22 @@ class BrainPlanner: loop_start_time=loop_start_time, ) + # 记录和展示计划日志 + logger.info( + f"{self.log_prefix}Planner: {reasoning}。选择了{len(actions)}个动作: {' '.join([a.action_type for a in actions])}" + ) + self.add_plan_log(reasoning, actions) + return actions async def build_planner_prompt( self, - is_group_chat: bool, chat_target_info: Optional["TargetPersonInfo"], current_available_actions: Dict[str, ActionInfo], message_id_list: List[Tuple[str, "DatabaseMessages"]], chat_content_block: str = "", interest: str = "", + prompt_key: str = "brain_planner_prompt_react", ) -> tuple[str, List[Tuple[str, "DatabaseMessages"]]]: """构建 Planner LLM 的提示词 (获取模板并填充数据)""" try: @@ -321,7 +369,7 @@ class BrainPlanner: name_block = f"你的名字是{bot_name}{bot_nickname},请注意哪些是你自己的发言。" # 获取主规划器模板并填充 - planner_prompt_template = await global_prompt_manager.get_prompt_async("brain_planner_prompt") + planner_prompt_template = await global_prompt_manager.get_prompt_async(prompt_key) prompt = planner_prompt_template.format( time_block=time_block, chat_context_description=chat_context_description, @@ -431,17 +479,18 @@ class BrainPlanner: filtered_actions: Dict[str, ActionInfo], available_actions: Dict[str, ActionInfo], loop_start_time: float, - ) -> List[ActionPlannerInfo]: + ) -> Tuple[str, List[ActionPlannerInfo]]: """执行主规划器""" llm_content = None actions: List[ActionPlannerInfo] = [] + extracted_reasoning = "" try: # 调用LLM llm_content, (reasoning_content, _, _) = await self.planner_llm.generate_response_async(prompt=prompt) - # logger.info(f"{self.log_prefix}规划器原始提示词: {prompt}") - # logger.info(f"{self.log_prefix}规划器原始响应: {llm_content}") + logger.info(f"{self.log_prefix}规划器原始提示词: {prompt}") + logger.info(f"{self.log_prefix}规划器原始响应: {llm_content}") if global_config.debug.show_planner_prompt: logger.info(f"{self.log_prefix}规划器原始提示词: {prompt}") @@ -456,10 +505,11 @@ class BrainPlanner: except Exception as req_e: logger.error(f"{self.log_prefix}LLM 请求执行失败: {req_e}") - return [ + extracted_reasoning = f"LLM 请求失败,模型出现问题: {req_e}" + return extracted_reasoning, [ ActionPlannerInfo( - action_type="no_reply", - reasoning=f"LLM 请求失败,模型出现问题: {req_e}", + action_type="complete_talk", + reasoning=extracted_reasoning, action_data={}, action_message=None, available_actions=available_actions, @@ -469,24 +519,32 @@ class BrainPlanner: # 解析LLM响应 if llm_content: try: - if json_objects := self._extract_json_from_markdown(llm_content): - logger.debug(f"{self.log_prefix}从响应中提取到{len(json_objects)}个JSON对象") + json_objects, extracted_reasoning = self._extract_json_from_markdown(llm_content) + 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}") filtered_actions_list = list(filtered_actions.items()) for json_obj in json_objects: - actions.extend(self._parse_single_action(json_obj, message_id_list, filtered_actions_list)) + parsed_actions = self._parse_single_action(json_obj, message_id_list, filtered_actions_list) + logger.info(f"{self.log_prefix}解析后的动作: {[a.action_type for a in parsed_actions]}") + actions.extend(parsed_actions) else: # 尝试解析为直接的JSON logger.warning(f"{self.log_prefix}LLM没有返回可用动作: {llm_content}") - actions = self._create_no_reply("LLM没有返回可用动作", available_actions) + extracted_reasoning = extracted_reasoning or "LLM没有返回可用动作" + actions = self._create_complete_talk(extracted_reasoning, available_actions) except Exception as json_e: logger.warning(f"{self.log_prefix}解析LLM响应JSON失败 {json_e}. LLM原始输出: '{llm_content}'") - actions = self._create_no_reply(f"解析LLM响应JSON失败: {json_e}", available_actions) + extracted_reasoning = f"解析LLM响应JSON失败: {json_e}" + actions = self._create_complete_talk(extracted_reasoning, available_actions) traceback.print_exc() else: - actions = self._create_no_reply("规划器没有获得LLM响应", available_actions) + extracted_reasoning = "规划器没有获得LLM响应" + actions = self._create_complete_talk(extracted_reasoning, available_actions) - # 添加循环开始时间到所有非no_reply动作 + # 添加循环开始时间到所有动作 for action in actions: action.action_data = action.action_data or {} action.action_data["loop_start_time"] = loop_start_time @@ -495,47 +553,136 @@ class BrainPlanner: f"{self.log_prefix}规划器决定执行{len(actions)}个动作: {' '.join([a.action_type for a in actions])}" ) - return actions + return extracted_reasoning, actions - def _create_no_reply(self, reasoning: str, available_actions: Dict[str, ActionInfo]) -> List[ActionPlannerInfo]: - """创建no_reply""" + def _create_complete_talk(self, reasoning: str, available_actions: Dict[str, ActionInfo]) -> List[ActionPlannerInfo]: + """创建complete_talk""" return [ ActionPlannerInfo( - action_type="no_reply", + action_type="complete_talk", reasoning=reasoning, action_data={}, action_message=None, available_actions=available_actions, ) ] + + def add_plan_log(self, reasoning: str, actions: List[ActionPlannerInfo]): + """添加计划日志""" + self.plan_log.append((reasoning, time.time(), actions)) + if len(self.plan_log) > 20: + self.plan_log.pop(0) - def _extract_json_from_markdown(self, content: str) -> List[dict]: + def _extract_json_from_markdown(self, content: str) -> Tuple[List[dict], str]: # sourcery skip: for-append-to-extend - """从Markdown格式的内容中提取JSON对象""" + """从Markdown格式的内容中提取JSON对象和推理内容""" json_objects = [] + reasoning_content = "" # 使用正则表达式查找```json包裹的JSON内容 json_pattern = r"```json\s*(.*?)\s*```" - matches = re.findall(json_pattern, content, re.DOTALL) + markdown_matches = re.findall(json_pattern, content, re.DOTALL) - for match in matches: + # 提取JSON之前的内容作为推理文本 + first_json_pos = len(content) + if markdown_matches: + # 找到第一个```json的位置 + first_json_pos = content.find("```json") + if first_json_pos > 0: + reasoning_content = content[:first_json_pos].strip() + # 清理推理内容中的注释标记 + reasoning_content = re.sub(r"^//\s*", "", reasoning_content, flags=re.MULTILINE) + reasoning_content = reasoning_content.strip() + + # 处理```json包裹的JSON + for match in markdown_matches: try: # 清理可能的注释和格式问题 json_str = re.sub(r"//.*?\n", "\n", match) # 移除单行注释 json_str = re.sub(r"/\*.*?\*/", "", json_str, flags=re.DOTALL) # 移除多行注释 if json_str := json_str.strip(): - json_obj = json.loads(repair_json(json_str)) - if isinstance(json_obj, dict): - json_objects.append(json_obj) - elif isinstance(json_obj, list): - for item in json_obj: - if isinstance(item, dict): - json_objects.append(item) + # 先尝试将整个块作为一个JSON对象或数组(适用于多行JSON) + try: + json_obj = json.loads(repair_json(json_str)) + if isinstance(json_obj, dict): + json_objects.append(json_obj) + elif isinstance(json_obj, list): + for item in json_obj: + if isinstance(item, dict): + json_objects.append(item) + except json.JSONDecodeError: + # 如果整个块解析失败,尝试按行分割(适用于多个单行JSON对象) + lines = [line.strip() for line in json_str.split("\n") if line.strip()] + for line in lines: + try: + # 尝试解析每一行作为独立的JSON对象 + json_obj = json.loads(repair_json(line)) + if isinstance(json_obj, dict): + json_objects.append(json_obj) + elif isinstance(json_obj, list): + for item in json_obj: + if isinstance(item, dict): + json_objects.append(item) + except json.JSONDecodeError: + # 单行解析失败,继续下一行 + continue except Exception as e: - logger.warning(f"解析JSON块失败: {e}, 块内容: {match[:100]}...") + logger.warning(f"{self.log_prefix}解析JSON块失败: {e}, 块内容: {match[:100]}...") continue - return json_objects + # 如果没有找到完整的```json```块,尝试查找不完整的代码块(缺少结尾```) + if not json_objects: + json_start_pos = content.find("```json") + if json_start_pos != -1: + # 找到```json之后的内容 + json_content_start = json_start_pos + 7 # ```json的长度 + # 提取从```json之后到内容结尾的所有内容 + incomplete_json_str = content[json_content_start:].strip() + + # 提取JSON之前的内容作为推理文本 + if json_start_pos > 0: + reasoning_content = content[:json_start_pos].strip() + reasoning_content = re.sub(r"^//\s*", "", reasoning_content, flags=re.MULTILINE) + reasoning_content = reasoning_content.strip() + + if incomplete_json_str: + try: + # 清理可能的注释和格式问题 + json_str = re.sub(r"//.*?\n", "\n", incomplete_json_str) + json_str = re.sub(r"/\*.*?\*/", "", json_str, flags=re.DOTALL) + json_str = json_str.strip() + + if json_str: + # 尝试按行分割,每行可能是一个JSON对象 + lines = [line.strip() for line in json_str.split("\n") if line.strip()] + for line in lines: + try: + json_obj = json.loads(repair_json(line)) + if isinstance(json_obj, dict): + json_objects.append(json_obj) + elif isinstance(json_obj, list): + for item in json_obj: + if isinstance(item, dict): + json_objects.append(item) + except json.JSONDecodeError: + pass + + # 如果按行解析没有成功,尝试将整个块作为一个JSON对象或数组 + if not json_objects: + try: + json_obj = json.loads(repair_json(json_str)) + if isinstance(json_obj, dict): + json_objects.append(json_obj) + elif isinstance(json_obj, list): + for item in json_obj: + if isinstance(item, dict): + json_objects.append(item) + except Exception as e: + logger.debug(f"尝试解析不完整的JSON代码块失败: {e}") + except Exception as e: + logger.debug(f"处理不完整的JSON代码块时出错: {e}") + + return json_objects, reasoning_content init_prompt() diff --git a/src/chat/heart_flow/heartFC_chat.py b/src/chat/heart_flow/heartFC_chat.py index 1af21a4f..eb101741 100644 --- a/src/chat/heart_flow/heartFC_chat.py +++ b/src/chat/heart_flow/heartFC_chat.py @@ -190,7 +190,7 @@ class HeartFChatting: limit_mode="latest", filter_mai=True, filter_command=False, - filter_no_read_command=True, + filter_intercept_message_level=0, ) # 根据连续 no_reply 次数动态调整阈值 @@ -485,7 +485,7 @@ class HeartFChatting: chat_id=self.stream_id, timestamp=time.time(), limit=int(global_config.chat.max_context_size * 0.6), - filter_no_read_command=True, + filter_intercept_message_level=1, ) chat_content_block, message_id_list = build_readable_messages_with_id( messages=message_list_before_now, diff --git a/src/chat/message_receive/bot.py b/src/chat/message_receive/bot.py index 2d798f54..1f5c7012 100644 --- a/src/chat/message_receive/bot.py +++ b/src/chat/message_receive/bot.py @@ -83,7 +83,7 @@ class ChatBot: self._started = True - async def _process_commands_with_new_system(self, message: MessageRecv): + async def _process_commands(self, message: MessageRecv): # sourcery skip: use-named-expression """使用新插件系统处理命令""" try: @@ -115,17 +115,17 @@ class ChatBot: try: # 执行命令 - success, response, intercept_message = await command_instance.execute() - message.is_no_read_command = bool(intercept_message) + success, response, intercept_message_level = await command_instance.execute() + message.intercept_message_level = intercept_message_level # 记录命令执行结果 if success: - logger.info(f"命令执行成功: {command_class.__name__} (拦截: {intercept_message})") + logger.info(f"命令执行成功: {command_class.__name__} (拦截等级: {intercept_message_level})") else: logger.warning(f"命令执行失败: {command_class.__name__} - {response}") # 根据命令的拦截设置决定是否继续处理消息 - return True, response, not intercept_message # 找到命令,根据intercept_message决定是否继续 + return True, response, not bool(intercept_message_level) # 找到命令,根据intercept_message决定是否继续 except Exception as e: logger.error(f"执行命令时出错: {command_class.__name__} - {e}") @@ -295,7 +295,7 @@ class ChatBot: # return # 命令处理 - 使用新插件系统检查并处理命令 - is_command, cmd_result, continue_process = await self._process_commands_with_new_system(message) + is_command, cmd_result, continue_process = await self._process_commands(message) # 如果是命令且不需要继续处理,则直接返回 if is_command and not continue_process: diff --git a/src/chat/message_receive/message.py b/src/chat/message_receive/message.py index 9528785e..727dd3b0 100644 --- a/src/chat/message_receive/message.py +++ b/src/chat/message_receive/message.py @@ -122,7 +122,7 @@ class MessageRecv(Message): self.is_notify = False self.is_command = False - self.is_no_read_command = False + self.intercept_message_level = 0 self.priority_mode = "interest" self.priority_info = None diff --git a/src/chat/message_receive/storage.py b/src/chat/message_receive/storage.py index b70f30ff..b73b04a3 100644 --- a/src/chat/message_receive/storage.py +++ b/src/chat/message_receive/storage.py @@ -72,7 +72,7 @@ class MessageStorage: key_words = "" key_words_lite = "" selected_expressions = message.selected_expressions - is_no_read_command = False + intercept_message_level = 0 else: filtered_display_message = "" interest_value = message.interest_value @@ -86,7 +86,7 @@ class MessageStorage: is_picid = message.is_picid is_notify = message.is_notify is_command = message.is_command - is_no_read_command = getattr(message, "is_no_read_command", False) + intercept_message_level = getattr(message, "intercept_message_level", 0) # 序列化关键词列表为JSON字符串 key_words = MessageStorage._serialize_keywords(message.key_words) key_words_lite = MessageStorage._serialize_keywords(message.key_words_lite) @@ -138,7 +138,7 @@ class MessageStorage: is_picid=is_picid, is_notify=is_notify, is_command=is_command, - is_no_read_command=is_no_read_command, + intercept_message_level=intercept_message_level, key_words=key_words, key_words_lite=key_words_lite, selected_expressions=selected_expressions, diff --git a/src/chat/planner_actions/action_modifier.py b/src/chat/planner_actions/action_modifier.py index 739d9999..baf1e1c5 100644 --- a/src/chat/planner_actions/action_modifier.py +++ b/src/chat/planner_actions/action_modifier.py @@ -69,7 +69,7 @@ class ActionModifier: chat_id=self.chat_stream.stream_id, timestamp=time.time(), limit=min(int(global_config.chat.max_context_size * 0.33), 10), - filter_no_read_command=True, + filter_intercept_message_level=1, ) chat_content = build_readable_messages( diff --git a/src/chat/planner_actions/planner.py b/src/chat/planner_actions/planner.py index 5c498e30..f8bab0bb 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/chat/planner_actions/planner.py @@ -316,7 +316,7 @@ class ActionPlanner: chat_id=self.chat_id, timestamp=time.time(), limit=int(global_config.chat.max_context_size * 0.6), - filter_no_read_command=True, + filter_intercept_message_level=1, ) message_id_list: list[Tuple[str, "DatabaseMessages"]] = [] chat_content_block, message_id_list = build_readable_messages_with_id( diff --git a/src/chat/replyer/group_generator.py b/src/chat/replyer/group_generator.py index 3dd52272..a37925c2 100644 --- a/src/chat/replyer/group_generator.py +++ b/src/chat/replyer/group_generator.py @@ -256,7 +256,7 @@ class DefaultReplyer: logger.debug(f"使用处理器选中的{len(selected_expressions)}个表达方式") for expr in selected_expressions: if isinstance(expr, dict) and "situation" in expr and "style" in expr: - style_habits.append(f"当{expr['situation']}时,使用 {expr['style']}") + style_habits.append(f"当{expr['situation']}时:{expr['style']}") else: logger.debug("没有从处理器获得表达方式,将使用空的表达方式") # 不再在replyer中进行随机选择,全部交给处理器处理 @@ -751,14 +751,14 @@ class DefaultReplyer: chat_id=chat_id, timestamp=reply_time_point, limit=global_config.chat.max_context_size * 1, - filter_no_read_command=True, + filter_intercept_message_level=1, ) message_list_before_short = get_raw_msg_before_timestamp_with_chat( chat_id=chat_id, timestamp=reply_time_point, limit=int(global_config.chat.max_context_size * 0.33), - filter_no_read_command=True, + filter_intercept_message_level=1, ) person_list_short: List[Person] = [] @@ -941,7 +941,7 @@ class DefaultReplyer: chat_id=chat_id, timestamp=time.time(), limit=min(int(global_config.chat.max_context_size * 0.33), 15), - filter_no_read_command=True, + filter_intercept_message_level=1, ) chat_talking_prompt_half = build_readable_messages( message_list_before_now_half, diff --git a/src/chat/replyer/private_generator.py b/src/chat/replyer/private_generator.py index 396e806f..726ce4b2 100644 --- a/src/chat/replyer/private_generator.py +++ b/src/chat/replyer/private_generator.py @@ -271,7 +271,7 @@ class PrivateReplyer: logger.debug(f"使用处理器选中的{len(selected_expressions)}个表达方式") for expr in selected_expressions: if isinstance(expr, dict) and "situation" in expr and "style" in expr: - style_habits.append(f"当{expr['situation']}时,使用 {expr['style']}") + style_habits.append(f"当{expr['situation']}时:{expr['style']}") else: logger.debug("没有从处理器获得表达方式,将使用空的表达方式") # 不再在replyer中进行随机选择,全部交给处理器处理 @@ -663,7 +663,7 @@ class PrivateReplyer: chat_id=chat_id, timestamp=time.time(), limit=global_config.chat.max_context_size, - filter_no_read_command=True, + filter_intercept_message_level=1, ) dialogue_prompt = build_readable_messages( @@ -678,7 +678,7 @@ class PrivateReplyer: chat_id=chat_id, timestamp=time.time(), limit=int(global_config.chat.max_context_size * 0.33), - filter_no_read_command=True, + filter_intercept_message_level=1, ) person_list_short: List[Person] = [] @@ -878,7 +878,7 @@ class PrivateReplyer: chat_id=chat_id, timestamp=time.time(), limit=min(int(global_config.chat.max_context_size * 0.33), 15), - filter_no_read_command=True, + filter_intercept_message_level=1, ) chat_talking_prompt_half = build_readable_messages( message_list_before_now_half, diff --git a/src/chat/replyer/prompt/replyer_prompt.py b/src/chat/replyer/prompt/replyer_prompt.py index f9ee25a4..c1c89124 100644 --- a/src/chat/replyer/prompt/replyer_prompt.py +++ b/src/chat/replyer/prompt/replyer_prompt.py @@ -19,7 +19,7 @@ def init_replyer_prompt(): {planner_reasoning} {identity} {chat_prompt}你正在群里聊天,现在请你读读之前的聊天记录,然后给出日常且口语化的回复,平淡一些,{mood_state} -尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。 +尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理。 {reply_style} 请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出一句回复内容就好。 不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。 @@ -39,7 +39,7 @@ def init_replyer_prompt(): {planner_reasoning} {identity} {chat_prompt}你正在和{sender_name}聊天,现在请你读读之前的聊天记录,然后给出日常且口语化的回复,平淡一些,{mood_state} -尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。 +尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理。 {reply_style} 请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。 {moderation_prompt}不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。""", diff --git a/src/chat/utils/chat_message_builder.py b/src/chat/utils/chat_message_builder.py index 5592e6cf..6a634fb4 100644 --- a/src/chat/utils/chat_message_builder.py +++ b/src/chat/utils/chat_message_builder.py @@ -120,7 +120,7 @@ def get_raw_msg_by_timestamp_with_chat( limit_mode: str = "latest", filter_bot=False, filter_command=False, - filter_no_read_command=False, + filter_intercept_message_level: Optional[int] = None, ) -> List[DatabaseMessages]: """获取在特定聊天从指定时间戳到指定时间戳的消息,按时间升序排序,返回消息列表 limit: 限制返回的消息数量,0为不限制 @@ -138,7 +138,7 @@ def get_raw_msg_by_timestamp_with_chat( limit_mode=limit_mode, filter_bot=filter_bot, filter_command=filter_command, - filter_no_read_command=filter_no_read_command, + filter_intercept_message_level=filter_intercept_message_level, ) @@ -150,7 +150,7 @@ def get_raw_msg_by_timestamp_with_chat_inclusive( limit_mode: str = "latest", filter_bot=False, filter_command=False, - filter_no_read_command=False, + filter_intercept_message_level: Optional[int] = None, ) -> List[DatabaseMessages]: """获取在特定聊天从指定时间戳到指定时间戳的消息(包含边界),按时间升序排序,返回消息列表 limit: 限制返回的消息数量,0为不限制 @@ -167,7 +167,7 @@ def get_raw_msg_by_timestamp_with_chat_inclusive( limit_mode=limit_mode, filter_bot=filter_bot, filter_command=filter_command, - filter_no_read_command=filter_no_read_command, + filter_intercept_message_level=filter_intercept_message_level, ) @@ -303,7 +303,7 @@ def get_raw_msg_before_timestamp(timestamp: float, limit: int = 0) -> List[Datab def get_raw_msg_before_timestamp_with_chat( - chat_id: str, timestamp: float, limit: int = 0, filter_no_read_command: bool = False + chat_id: str, timestamp: float, limit: int = 0, filter_intercept_message_level: Optional[int] = None ) -> List[DatabaseMessages]: """获取指定时间戳之前的消息,按时间升序排序,返回消息列表 limit: 限制返回的消息数量,0为不限制 @@ -311,7 +311,7 @@ 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_no_read_command=filter_no_read_command + 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 fa865d48..4a115e06 100644 --- a/src/chat/utils/statistic.py +++ b/src/chat/utils/statistic.py @@ -8,7 +8,7 @@ from typing import Any, Dict, Tuple, List from src.common.logger import get_logger from src.common.database.database import db -from src.common.database.database_model import OnlineTime, LLMUsage, Messages +from src.common.database.database_model import OnlineTime, LLMUsage, Messages, ActionRecords from src.manager.async_task_manager import AsyncTask from src.manager.local_store_manager import local_storage from src.config.config import global_config @@ -505,13 +505,6 @@ class StatisticOutputTask(AsyncTask): for period_key, _ in collect_period } - # 获取bot的QQ账号 - bot_qq_account = ( - str(global_config.bot.qq_account) - if hasattr(global_config, "bot") and hasattr(global_config.bot, "qq_account") - else "" - ) - query_start_timestamp = collect_period[-1][1].timestamp() # Messages.time is a DoubleField (timestamp) for message in Messages.select().where(Messages.time >= query_start_timestamp): # type: ignore message_time_ts = message.time # This is a float timestamp @@ -537,7 +530,7 @@ class StatisticOutputTask(AsyncTask): if not chat_id: # Should not happen if above logic is correct continue - # Update name_mapping + # Update name_mapping(仅用于展示聊天名称) try: if chat_id in self.name_mapping: if chat_name != self.name_mapping[chat_id][0] and message_time_ts > self.name_mapping[chat_id][1]: @@ -549,19 +542,30 @@ class StatisticOutputTask(AsyncTask): # 重置为正确的格式 self.name_mapping[chat_id] = (chat_name, message_time_ts) - # 检查是否是bot发送的消息(回复) - is_bot_reply = False - if bot_qq_account and message.user_id == bot_qq_account: - is_bot_reply = True - for idx, (_, period_start_dt) in enumerate(collect_period): if message_time_ts >= period_start_dt.timestamp(): for period_key, _ in collect_period[idx:]: stats[period_key][TOTAL_MSG_CNT] += 1 stats[period_key][MSG_CNT_BY_CHAT][chat_id] += 1 - if is_bot_reply: - stats[period_key][TOTAL_REPLY_CNT] += 1 break + + # 使用 ActionRecords 中的 reply 动作次数作为回复数基准 + try: + action_query_start_timestamp = collect_period[-1][1].timestamp() + for action in ActionRecords.select().where(ActionRecords.time >= action_query_start_timestamp): # type: ignore + # 仅统计已完成的 reply 动作 + if action.action_name != "reply" or not action.action_done: + continue + + action_time_ts = action.time + for idx, (_, period_start_dt) in enumerate(collect_period): + if action_time_ts >= period_start_dt.timestamp(): + for period_key, _ in collect_period[idx:]: + stats[period_key][TOTAL_REPLY_CNT] += 1 + break + except Exception as e: + logger.warning(f"统计 reply 动作次数失败,将回复数视为 0,错误信息:{e}") + return stats def _collect_all_statistics(self, now: datetime) -> Dict[str, Dict[str, Any]]: diff --git a/src/common/data_models/database_data_model.py b/src/common/data_models/database_data_model.py index 9707add8..5bd35873 100644 --- a/src/common/data_models/database_data_model.py +++ b/src/common/data_models/database_data_model.py @@ -77,7 +77,7 @@ class DatabaseMessages(BaseDataModel): is_emoji: bool = False, is_picid: bool = False, is_command: bool = False, - is_no_read_command: bool = False, + intercept_message_level: int = 0, is_notify: bool = False, selected_expressions: Optional[str] = None, user_id: str = "", @@ -120,7 +120,7 @@ class DatabaseMessages(BaseDataModel): self.is_emoji = is_emoji self.is_picid = is_picid self.is_command = is_command - self.is_no_read_command = is_no_read_command + self.intercept_message_level = intercept_message_level self.is_notify = is_notify self.selected_expressions = selected_expressions @@ -188,7 +188,7 @@ class DatabaseMessages(BaseDataModel): "is_emoji": self.is_emoji, "is_picid": self.is_picid, "is_command": self.is_command, - "is_no_read_command": self.is_no_read_command, + "intercept_message_level": self.intercept_message_level, "is_notify": self.is_notify, "selected_expressions": self.selected_expressions, "user_id": self.user_info.user_id, diff --git a/src/common/data_models/message_data_model.py b/src/common/data_models/message_data_model.py index 3c4c5505..dc4ad951 100644 --- a/src/common/data_models/message_data_model.py +++ b/src/common/data_models/message_data_model.py @@ -22,7 +22,7 @@ class MessageAndActionModel(BaseDataModel): is_action_record: bool = field(default=False) action_name: Optional[str] = None is_command: bool = field(default=False) - is_no_read_command: bool = field(default=False) + intercept_message_level: int = field(default=0) @classmethod def from_DatabaseMessages(cls, message: "DatabaseMessages"): @@ -37,7 +37,7 @@ class MessageAndActionModel(BaseDataModel): display_message=message.display_message, chat_info_platform=message.chat_info.platform, is_command=message.is_command, - is_no_read_command=getattr(message, "is_no_read_command", False), + intercept_message_level=getattr(message, "intercept_message_level", 0), ) diff --git a/src/common/database/database_model.py b/src/common/database/database_model.py index 9b1f18df..5e916317 100644 --- a/src/common/database/database_model.py +++ b/src/common/database/database_model.py @@ -170,7 +170,7 @@ class Messages(BaseModel): is_emoji = BooleanField(default=False) is_picid = BooleanField(default=False) is_command = BooleanField(default=False) - is_no_read_command = BooleanField(default=False) + intercept_message_level = IntegerField(default=0) is_notify = BooleanField(default=False) selected_expressions = TextField(null=True) @@ -324,7 +324,6 @@ class Expression(BaseModel): # new mode fields context = TextField(null=True) - up_content = TextField(null=True) content_list = TextField(null=True) count = IntegerField(default=1) diff --git a/src/common/message_repository.py b/src/common/message_repository.py index 4b9c6b35..fa0126d4 100644 --- a/src/common/message_repository.py +++ b/src/common/message_repository.py @@ -25,7 +25,7 @@ def find_messages( limit_mode: str = "latest", filter_bot=False, filter_command=False, - filter_no_read_command=False, + filter_intercept_message_level: Optional[int] = None, ) -> List[DatabaseMessages]: """ 根据提供的过滤器、排序和限制条件查找消息。 @@ -85,8 +85,9 @@ def find_messages( # 使用按位取反构造 Peewee 的 NOT 条件,避免直接与 False 比较 query = query.where(~Messages.is_command) - if filter_no_read_command: - query = query.where(~Messages.is_no_read_command) + if filter_intercept_message_level is not None: + # 过滤掉所有 intercept_message_level > filter_intercept_message_level 的消息 + query = query.where(Messages.intercept_message_level <= filter_intercept_message_level) if limit > 0: if limit_mode == "earliest": diff --git a/src/common/toml_utils.py b/src/common/toml_utils.py index 0c34f6ab..0a88c458 100644 --- a/src/common/toml_utils.py +++ b/src/common/toml_utils.py @@ -4,6 +4,7 @@ TOML 工具函数 提供 TOML 文件的格式化保存功能,确保数组等元素以美观的多行格式输出。 """ +import re from typing import Any import tomlkit from tomlkit.items import AoT, Table, Array @@ -54,14 +55,71 @@ def _format_toml_value(obj: Any, threshold: int, depth: int = 0) -> Any: return obj -def save_toml_with_format(data: Any, file_path: str, multiline_threshold: int = 1) -> None: - """格式化 TOML 数据并保存到文件""" +def _update_toml_doc(target: Any, source: Any) -> None: + """ + 递归合并字典,将 source 的值更新到 target 中,保留 target 的注释和格式。 + - 已存在的键:更新值(递归处理嵌套字典) + - 新增的键:添加到 target + - 跳过 version 字段 + """ + if isinstance(source, list) or not isinstance(source, dict) or not isinstance(target, dict): + return + + for key, value in source.items(): + if key == "version": + continue + if key in target: + # 已存在的键:递归更新或直接赋值 + target_value = target[key] + if isinstance(value, dict) and isinstance(target_value, dict): + _update_toml_doc(target_value, value) + else: + try: + target[key] = tomlkit.item(value) + except (TypeError, ValueError): + target[key] = value + else: + # 新增的键:添加到 target + try: + target[key] = tomlkit.item(value) + except (TypeError, ValueError): + target[key] = value + + +def save_toml_with_format( + data: Any, file_path: str, multiline_threshold: int = 1, preserve_comments: bool = True +) -> None: + """ + 格式化 TOML 数据并保存到文件。 + + Args: + data: 要保存的数据(dict 或 tomlkit 文档) + file_path: 保存路径 + multiline_threshold: 数组多行格式化阈值,-1 表示不格式化 + preserve_comments: 是否保留原文件的注释和格式(默认 True) + 若为 True 且文件已存在且 data 不是 tomlkit 文档,会先读取原文件,再将 data 合并进去 + """ + import os + from tomlkit import TOMLDocument + + # 如果需要保留注释、文件存在、且 data 不是已有的 tomlkit 文档,先读取原文件再合并 + if preserve_comments and os.path.exists(file_path) and not isinstance(data, TOMLDocument): + with open(file_path, "r", encoding="utf-8") as f: + doc = tomlkit.load(f) + _update_toml_doc(doc, data) + data = doc + 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) with open(file_path, "w", encoding="utf-8") as f: - tomlkit.dump(formatted, f) + f.write(output) def format_toml_string(data: Any, multiline_threshold: int = 1) -> str: """格式化 TOML 数据并返回字符串""" formatted = _format_toml_value(data, multiline_threshold) if multiline_threshold >= 0 else data - return tomlkit.dumps(formatted) \ No newline at end of file + output = tomlkit.dumps(formatted) + # 规范化:将 3+ 连续空行压缩为 1 个空行,防止空行累积 + return re.sub(r'\n{3,}', '\n\n', output) \ No newline at end of file diff --git a/src/config/api_ada_configs.py b/src/config/api_ada_configs.py index 897e1f87..a5d5f059 100644 --- a/src/config/api_ada_configs.py +++ b/src/config/api_ada_configs.py @@ -60,6 +60,12 @@ class ModelInfo(ConfigBase): price_out: float = field(default=0.0) """每M token输出价格""" + temperature: float | None = field(default=None) + """模型级别温度(可选),会覆盖任务配置中的温度""" + + max_tokens: int | None = field(default=None) + """模型级别最大token数(可选),会覆盖任务配置中的max_tokens""" + force_stream_mode: bool = field(default=False) """是否强制使用流式输出模式""" diff --git a/src/config/config.py b/src/config/config.py index 9342cbb4..061fa07d 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -35,6 +35,7 @@ from src.config.official_configs import ( MemoryConfig, DebugConfig, JargonConfig, + DreamConfig, ) from .api_ada_configs import ( @@ -57,7 +58,7 @@ TEMPLATE_DIR = os.path.join(PROJECT_ROOT, "template") # 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码 # 对该字段的更新,请严格参照语义化版本规范:https://semver.org/lang/zh-CN/ -MMC_VERSION = "0.11.6" +MMC_VERSION = "0.11.7-snapshot.1" def get_key_comment(toml_table, key): @@ -357,6 +358,7 @@ class Config(ConfigBase): mood: MoodConfig voice: VoiceConfig jargon: JargonConfig + dream: DreamConfig @dataclass diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 5e88f8cd..3e93b56f 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -173,7 +173,11 @@ class ChatConfig(ConfigBase): def get_talk_value(self, chat_id: Optional[str]) -> float: """根据规则返回当前 chat 的动态 talk_value,未匹配则回退到基础值。""" if not self.enable_talk_value_rules or not self.talk_value_rules: - return self.talk_value + result = self.talk_value + # 防止返回0值,自动转换为0.0001 + if result == 0: + return 0.0000001 + return result now_min = self._now_minutes() @@ -199,7 +203,11 @@ class ChatConfig(ConfigBase): start_min, end_min = parsed if self._in_range(now_min, start_min, end_min): try: - return float(value) + result = float(value) + # 防止返回0值,自动转换为0.0001 + if result == 0: + return 0.0000001 + return result except Exception: continue @@ -218,12 +226,20 @@ class ChatConfig(ConfigBase): start_min, end_min = parsed if self._in_range(now_min, start_min, end_min): try: - return float(value) + result = float(value) + # 防止返回0值,自动转换为0.0001 + if result == 0: + return 0.0000001 + return result except Exception: continue # 3) 未命中规则返回基础值 - return self.talk_value + result = self.talk_value + # 防止返回0值,自动转换为0.0001 + if result == 0: + return 0.0000001 + return result @dataclass @@ -247,6 +263,9 @@ class MemoryConfig(ConfigBase): enable_jargon_detection: bool = True """记忆检索过程中是否启用黑话识别""" + global_memory: bool = False + """是否允许记忆检索在聊天记录中进行全局查询(忽略当前chat_id,仅对 search_chat_history 等工具生效)""" + def __post_init__(self): """验证配置值""" if self.max_agent_iterations < 1: @@ -342,22 +361,30 @@ class ExpressionConfig(ConfigBase): tuple: (是否使用表达, 是否学习表达, 学习间隔) """ if not self.learning_list: - # 如果没有配置,使用默认值:启用表达,启用学习,300秒间隔 - return True, True, 300 + # 如果没有配置,使用默认值:启用表达,启用学习,学习强度1.0(对应300秒间隔) + return True, True, 1.0 # 优先检查聊天流特定的配置 if chat_stream_id: specific_expression_config = self._get_stream_specific_config(chat_stream_id) if specific_expression_config is not None: - return specific_expression_config + use_expression, enable_learning, learning_intensity = specific_expression_config + # 防止学习强度为0,自动转换为0.0001 + if learning_intensity == 0: + learning_intensity = 0.0000001 + return use_expression, enable_learning, learning_intensity # 检查全局配置(第一个元素为空字符串的配置) global_expression_config = self._get_global_config() if global_expression_config is not None: - return global_expression_config + use_expression, enable_learning, learning_intensity = global_expression_config + # 防止学习强度为0,自动转换为0.0001 + if learning_intensity == 0: + learning_intensity = 0.0000001 + return use_expression, enable_learning, learning_intensity - # 如果都没有匹配,返回默认值 - return True, True, 300 + # 如果都没有匹配,返回默认值:启用表达,启用学习,学习强度1.0(对应300秒间隔) + return True, True, 1.0 def _get_stream_specific_config(self, chat_stream_id: str) -> Optional[tuple[bool, bool, int]]: """ @@ -393,6 +420,9 @@ class ExpressionConfig(ConfigBase): use_expression: bool = config_item[1].lower() == "enable" enable_learning: bool = config_item[2].lower() == "enable" learning_intensity: float = float(config_item[3]) + # 防止学习强度为0,自动转换为0.0001 + if learning_intensity == 0: + learning_intensity = 0.0000001 return use_expression, enable_learning, learning_intensity # type: ignore except (ValueError, IndexError): continue @@ -416,6 +446,9 @@ class ExpressionConfig(ConfigBase): use_expression: bool = config_item[1].lower() == "enable" enable_learning: bool = config_item[2].lower() == "enable" learning_intensity = float(config_item[3]) + # 防止学习强度为0,自动转换为0.0001 + if learning_intensity == 0: + learning_intensity = 0.0000001 return use_expression, enable_learning, learning_intensity # type: ignore except (ValueError, IndexError): continue @@ -714,3 +747,89 @@ class JargonConfig(ConfigBase): all_global: bool = False """是否将所有新增的jargon项目默认为全局(is_global=True),chat_id记录第一次存储时的id""" + + +@dataclass +class DreamConfig(ConfigBase): + """Dream配置类""" + + interval_minutes: int = 30 + """做梦时间间隔(分钟),默认30分钟""" + + max_iterations: int = 20 + """做梦最大轮次,默认20轮""" + + first_delay_seconds: int = 60 + """程序启动后首次做梦前的延迟时间(秒),默认60秒""" + + dream_time_ranges: list[str] = field(default_factory=lambda: []) + """ + 做梦时间段配置列表,格式:["HH:MM-HH:MM", ...] + 如果列表为空,则表示全天允许做梦。 + 如果配置了时间段,则只有在这些时间段内才会实际执行做梦流程。 + 时间段外,调度器仍会按间隔检查,但不会进入做梦流程。 + + 示例: + [ + "09:00-22:00", # 白天允许做梦 + "23:00-02:00", # 跨夜时间段(23:00到次日02:00) + ] + + 支持跨夜区间,例如 "23:00-02:00" 表示从23:00到次日02:00。 + """ + + def _now_minutes(self) -> int: + """返回本地时间的分钟数(0-1439)。""" + lt = time.localtime() + return lt.tm_hour * 60 + lt.tm_min + + def _parse_range(self, range_str: str) -> Optional[tuple[int, int]]: + """解析 "HH:MM-HH:MM" 到 (start_min, end_min)。""" + try: + start_str, end_str = [s.strip() for s in range_str.split("-")] + sh, sm = [int(x) for x in start_str.split(":")] + eh, em = [int(x) for x in end_str.split(":")] + return sh * 60 + sm, eh * 60 + em + except Exception: + return None + + def _in_range(self, now_min: int, start_min: int, end_min: int) -> bool: + """ + 判断 now_min 是否在 [start_min, end_min] 区间内。 + 支持跨夜:如果 start > end,则表示跨越午夜。 + """ + if start_min <= end_min: + return start_min <= now_min <= end_min + # 跨夜:例如 23:00-02:00 + return now_min >= start_min or now_min <= end_min + + def is_in_dream_time(self) -> bool: + """ + 检查当前时间是否在允许做梦的时间段内。 + 如果 dream_time_ranges 为空,则返回 True(全天允许)。 + """ + 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 + parsed = self._parse_range(time_range) + if not parsed: + continue + start_min, end_min = parsed + if self._in_range(now_min, start_min, end_min): + return True + + return False + + def __post_init__(self): + """验证配置值""" + if self.interval_minutes < 1: + raise ValueError(f"interval_minutes 必须至少为1,当前值: {self.interval_minutes}") + 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 diff --git a/src/dream/dream_agent.py b/src/dream/dream_agent.py new file mode 100644 index 00000000..c14f8061 --- /dev/null +++ b/src/dream/dream_agent.py @@ -0,0 +1,558 @@ +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.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 +from src.dream.dream_generator import generate_dream_summary + +# dream 工具工厂函数 +from src.dream.tools.search_chat_history_tool import make_search_chat_history +from src.dream.tools.get_chat_history_detail_tool import make_get_chat_history_detail +from src.dream.tools.delete_chat_history_tool import make_delete_chat_history +from src.dream.tools.create_chat_history_tool import make_create_chat_history +from src.dream.tools.update_chat_history_tool import make_update_chat_history +from src.dream.tools.finish_maintenance_tool import make_finish_maintenance +from src.dream.tools.search_jargon_tool import make_search_jargon +from src.dream.tools.delete_jargon_tool import make_delete_jargon +from src.dream.tools.update_jargon_tool import make_update_jargon + +logger = get_logger("dream_agent") + + +def init_dream_prompts() -> None: + """初始化 dream agent 的提示词""" + Prompt( + """ +你的名字是{bot_name},你现在处于"梦境维护模式(dream agent)"。 +你可以自由地在 ChatHistory 库中探索、整理、创建和删改记录,以帮助自己在未来更好地回忆和理解对话历史。 + +本轮要维护的聊天ID:{chat_id} +本轮随机选中的起始记忆 ID:{start_memory_id} +请优先以这条起始记忆为切入点,先理解它的内容与上下文,再决定如何在其附近进行创建新概括、重写或删除等整理操作;如果起始记忆为空,则由你自行选择合适的切入点。 + +你可以使用的工具包括: +**ChatHistory 维护工具:** +- search_chat_history:根据关键词或参与人搜索该 chat_id 下的历史记忆概括列表 +- get_chat_history_detail:查看某条概括的详细内容 +- create_chat_history:根据整理后的理解创建一条新的 ChatHistory 概括记录(主题、概括、关键词、关键信息等) +- update_chat_history:在不改变事实的前提下重写或精炼主题、概括、关键词、关键信息 +- delete_chat_history:删除明显冗余、噪声、错误或无意义的记录,或者非常有时效性的信息,或者无太多有用信息的日常互动。 +你也可以先用 create_chat_history 创建一条新的综合概括,再对旧的冗余记录执行多次 delete_chat_history 来完成“合并”效果。 + +**Jargon(黑话)维护工具(只读,禁止修改):** +- search_jargon:根据一个或多个关键词搜索Jargon 记录,通常是含义不明确的词条或者特殊的缩写 + +**通用工具:** +- finish_maintenance:当你认为当前维护工作已经完成,没有更多需要整理的内容时,调用此工具来结束本次运行 + +**工作目标**: +- 发现冗余、重复或高度相似的记录,并进行合并或删除; +- 发现主题/概括过于含糊、啰嗦或缺少关键信息的记录,进行重写和精简; +- summary要尽可能保持有用的信息; +- 尽量保持信息的真实与可用性,不要凭空捏造事实。 + +**合并准则** +- 你可以新建一个记录,然后删除旧记录来实现合并。 +- 如果两个或多个记录的主题相似,内容是对主题不同方面的信息或讨论,且信息量较少,则可以合并为一条记录。 +- 如果两个记录冲突,可以根据逻辑保留一个或者进行整合,也可以采取更新的记录,删除旧的记录 + +**轮次信息**: +- 本次维护最多执行 {max_iterations} 轮 +- 每轮开始时,系统会告知你当前是第几轮,还剩多少轮 +- 如果提前完成维护工作,可以调用 finish_maintenance 工具主动结束 + +**每一轮的执行方式(必须遵守):** +- 第一步:先用一小段中文自然语言,写出你的「思考」和本轮计划(例如要查什么、准备怎么合并/修改); +- 第二步:在这段思考之后,再通过工具调用来执行你的计划(可以调用 0~N 个工具); +- 第三步:收到工具结果后,在下一轮继续先写出新的思考,再视情况继续调用工具。 + +请不要在没有先写出思考的情况下直接调用工具。 +只输出你的思考内容或工具调用结果,由系统负责真正执行工具调用。 +""", + name="dream_react_head_prompt", + ) + + + +class DreamTool: + """dream 模块内部使用的简易工具封装""" + + def __init__(self, name: str, description: str, parameters: List[Tuple], execute_func): + self.name = name + self.description = description + self.parameters = parameters + self.execute_func = execute_func + + def get_tool_definition(self) -> Dict[str, Any]: + return { + "name": self.name, + "description": self.description, + "parameters": self.parameters, + } + + async def execute(self, **kwargs) -> str: + return await self.execute_func(**kwargs) + + +class DreamToolRegistry: + def __init__(self) -> None: + self.tools: Dict[str, DreamTool] = {} + + def register_tool(self, tool: DreamTool) -> None: + """ + 注册或更新 dream 工具。 + 注意:dream agent 每个 chat_id 会重新初始化工具,这里允许覆盖已有同名工具。 + """ + self.tools[tool.name] = tool + logger.info(f"注册/更新 dream 工具: {tool.name}") + + def get_tool(self, name: str) -> Optional[DreamTool]: + return self.tools.get(name) + + def get_tool_definitions(self) -> List[Dict[str, Any]]: + return [tool.get_tool_definition() for tool in self.tools.values()] + + +_dream_tool_registry = DreamToolRegistry() + + +def get_dream_tool_registry() -> DreamToolRegistry: + return _dream_tool_registry + + +def init_dream_tools(chat_id: str) -> None: + """注册 dream agent 可用的 ChatHistory / Jargon 相关工具(限定在当前 chat_id 作用域内)""" + from src.llm_models.payload_content.tool_option import ToolParamType + + # 通过工厂函数生成绑定当前 chat_id 的工具实现 + search_chat_history = make_search_chat_history(chat_id) + get_chat_history_detail = make_get_chat_history_detail(chat_id) + delete_chat_history = make_delete_chat_history(chat_id) + create_chat_history = make_create_chat_history(chat_id) + update_chat_history = make_update_chat_history(chat_id) + finish_maintenance = make_finish_maintenance(chat_id) + + search_jargon = make_search_jargon(chat_id) + delete_jargon = make_delete_jargon(chat_id) + update_jargon = make_update_jargon(chat_id) + + _dream_tool_registry.register_tool( + DreamTool( + "search_chat_history", + "根据关键词或参与人查询当前 chat_id 下的 ChatHistory 概览,便于快速定位相关记忆。", + [ + ("keyword", ToolParamType.STRING, "关键词(可选,支持多个关键词,可用空格、逗号等分隔)。", False, None), + ("participant", ToolParamType.STRING, "参与人昵称(可选)。", False, None), + ], + search_chat_history, + ) + ) + + _dream_tool_registry.register_tool( + DreamTool( + "get_chat_history_detail", + "根据 memory_id 获取单条 ChatHistory 的详细内容,包含主题、概括、关键词、关键信息等字段(不包含原文)。", + [ + ("memory_id", ToolParamType.INTEGER, "ChatHistory 主键 ID。", True, None), + ], + get_chat_history_detail, + ) + ) + + _dream_tool_registry.register_tool( + DreamTool( + "delete_chat_history", + "根据 memory_id 删除一条 ChatHistory 记录(请谨慎使用)。", + [ + ("memory_id", ToolParamType.INTEGER, "需要删除的 ChatHistory 主键 ID。", True, None), + ], + delete_chat_history, + ) + ) + + _dream_tool_registry.register_tool( + DreamTool( + "update_chat_history", + "按字段更新 ChatHistory 记录,可用于清理、重写或补充信息。", + [ + ("memory_id", ToolParamType.INTEGER, "需要更新的 ChatHistory 主键 ID。", True, None), + ("theme", ToolParamType.STRING, "新的主题标题,如果不需要修改可不填。", False, None), + ("summary", ToolParamType.STRING, "新的概括内容,如果不需要修改可不填。", False, None), + ("keywords", ToolParamType.STRING, "新的关键词 JSON 字符串,如 ['关键词1','关键词2']。", False, None), + ("key_point", ToolParamType.STRING, "新的关键信息 JSON 字符串,如 ['要点1','要点2']。", False, None), + ], + update_chat_history, + ) + ) + + _dream_tool_registry.register_tool( + DreamTool( + "create_chat_history", + "根据整理后的理解创建一条新的 ChatHistory 概括记录(主题、概括、关键词、关键信息等)。", + [ + ("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), + ("start_time", ToolParamType.STRING, "起始时间戳(秒,Unix 时间,必填)。", True, None), + ("end_time", ToolParamType.STRING, "结束时间戳(秒,Unix 时间,必填)。", True, None), + ], + create_chat_history, + ) + ) + + _dream_tool_registry.register_tool( + DreamTool( + "finish_maintenance", + "结束本次 dream 维护任务。当你认为当前 chat_id 下的维护工作已经完成,没有更多需要整理、合并或修改的内容时,调用此工具来主动结束本次运行。", + [ + ("reason", ToolParamType.STRING, "结束维护的原因说明(可选),例如 '已完成所有记录的整理' 或 '当前记录质量良好,无需进一步维护'。", False, None), + ], + finish_maintenance, + ) + ) + + # ==================== Jargon 维护工具 ==================== + # 注册 Jargon 工具 + _dream_tool_registry.register_tool( + DreamTool( + "search_jargon", + "根据一个或多个关键词搜索当前 chat_id 相关的 Jargon 记录概览(只包含 is_jargon=True,含全局 Jargon),便于快速理解黑话库。", + [ + ("keyword", ToolParamType.STRING, "按一个或多个关键词搜索内容/含义/推断结果(必填)。", True, None), + ], + search_jargon, + ) + ) + + +async def run_dream_agent_once( + chat_id: str, + max_iterations: Optional[int] = None, + start_memory_id: Optional[int] = None, +) -> None: + """ + 运行一次 dream agent,对指定 chat_id 的 ChatHistory 进行最多 max_iterations 轮的整理。 + 如果 max_iterations 为 None,则使用配置文件中的默认值。 + """ + 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} 轮") + + # 初始化工具(作用域限定在当前 chat_id) + init_dream_tools(chat_id) + + tool_registry = get_dream_tool_registry() + tool_defs = tool_registry.get_tool_definitions() + + bot_name = global_config.bot.nickname + time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + + head_prompt = await global_prompt_manager.format_prompt( + "dream_react_head_prompt", + bot_name=bot_name, + time_now=time_now, + chat_id=chat_id, + start_memory_id=start_memory_id if start_memory_id is not None else "无(本轮由你自由选择切入点)", + max_iterations=max_iterations, + ) + + conversation_messages: List[Message] = [] + + # 如果提供了起始记忆 ID,则在对话正式开始前,先把这条记忆的详细信息放入上下文, + # 避免 LLM 还需要额外调用一次 get_chat_history_detail 才能看到起始记忆内容。 + if start_memory_id is not None: + try: + record = ChatHistory.get_or_none(ChatHistory.id == start_memory_id) + if record: + start_time_str = ( + 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 "未知" + ) + detail_text = ( + f"ID={record.id}\n" + f"chat_id={record.chat_id}\n" + f"时间范围={start_time_str} 至 {end_time_str}\n" + f"主题={record.theme or '无'}\n" + f"关键词={record.keywords or '无'}\n" + f"参与者={record.participants or '无'}\n" + f"概括={record.summary or '无'}\n" + f"关键信息={record.key_point or '无'}" + ) + + logger.debug( + f"[dream] 预加载起始记忆详情 memory_id={start_memory_id}," + f"预览: {detail_text[:200].replace(chr(10), ' ')}" + ) + + start_detail_builder = MessageBuilder() + start_detail_builder.set_role(RoleType.User) + start_detail_builder.add_text_content( + "【起始记忆详情】以下是本轮随机/指定的起始记忆的详细信息,供你在整理时优先参考:\n\n" + + detail_text + ) + conversation_messages.append(start_detail_builder.build()) + else: + logger.warning( + f"[dream] 提供的 start_memory_id={start_memory_id} 未找到对应 ChatHistory 记录," + "将不预加载起始记忆详情。" + ) + except Exception as e: + logger.error(f"[dream] 预加载起始记忆详情失败 start_memory_id={start_memory_id}: {e}") + + # 注意:message_factory 必须是同步函数,返回消息列表(不能是 async/coroutine) + def message_factory( + _client, + *, + _head_prompt: str = head_prompt, + _conversation_messages: List[Message] = conversation_messages, + ) -> List[Message]: + messages: List[Message] = [] + system_builder = MessageBuilder() + system_builder.set_role(RoleType.System) + system_builder.add_text_content(_head_prompt) + messages.append(system_builder.build()) + messages.extend(_conversation_messages) + return messages + + for iteration in range(1, max_iterations + 1): + # 在每轮开始时,添加轮次信息到对话中 + remaining_rounds = max_iterations - iteration + 1 + round_info_builder = MessageBuilder() + round_info_builder.set_role(RoleType.User) + round_info_builder.add_text_content( + f"【轮次信息】当前是第 {iteration}/{max_iterations} 轮,还剩 {remaining_rounds} 轮。" + ) + 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", + ) + ) + + if not success: + logger.error(f"[dream] 第 {iteration} 轮 LLM 调用失败: {response}") + break + + # 先输出「思考」内容,再输出工具调用信息(思考文本较长,仅在 debug 下输出) + thought_log = reasoning_content or (response[:300] if response else "") + if thought_log: + logger.debug(f"[dream] 第 {iteration} 轮思考内容: {thought_log}") + + logger.info( + f"[dream] 第 {iteration} 轮响应,模型={model_name},工具调用数={len(tool_calls) if tool_calls else 0}" + ) + + assistant_msg: Optional[Message] = None + if tool_calls: + builder = MessageBuilder() + builder.set_role(RoleType.Assistant) + if response and response.strip(): + builder.add_text_content(response) + builder.set_tool_calls(tool_calls) + assistant_msg = builder.build() + elif response and response.strip(): + builder = MessageBuilder() + builder.set_role(RoleType.Assistant) + builder.add_text_content(response) + assistant_msg = builder.build() + + if assistant_msg: + conversation_messages.append(assistant_msg) + + # 如果本轮没有工具调用,仅作为思考记录,继续下一轮 + if not tool_calls: + logger.debug(f"[dream] 第 {iteration} 轮未调用任何工具,仅记录思考。") + continue + + # 执行所有工具调用 + tasks = [] + finish_maintenance_called = False + for tc in tool_calls: + tool = tool_registry.get_tool(tc.func_name) + if not tool: + logger.warning(f"[dream] 未知工具:{tc.func_name}") + continue + + # 检测是否调用了 finish_maintenance 工具 + if tc.func_name == "finish_maintenance": + finish_maintenance_called = True + + params = tc.args or {} + + async def _run_single(t: DreamTool, p: Dict[str, Any], call_id: str, it: int): + try: + result = await t.execute(**p) + logger.debug(f"[dream] 第 {it} 轮 工具 {t.name} 执行完成") + return call_id, result + except Exception as e: + logger.error(f"[dream] 工具 {t.name} 执行失败: {e}") + return call_id, f"工具 {t.name} 执行失败: {e}" + + tasks.append(_run_single(tool, params, tc.call_id, iteration)) + + if not tasks: + continue + + tool_results = await asyncio.gather(*tasks, return_exceptions=False) + + # 将工具结果作为 Tool 消息追加 + for call_id, obs in tool_results: + tool_builder = MessageBuilder() + tool_builder.set_role(RoleType.Tool) + tool_builder.add_text_content(str(obs)) + tool_builder.add_tool_call(call_id) + conversation_messages.append(tool_builder.build()) + + # 如果调用了 finish_maintenance 工具,提前结束本次运行 + if finish_maintenance_called: + logger.info(f"[dream] 第 {iteration} 轮检测到 finish_maintenance 工具调用,提前结束本次维护。") + break + + cost = time.time() - start_ts + logger.info(f"[dream] 对 chat_id={chat_id} 的 dream 维护结束,共迭代 {iteration} 轮,耗时 {cost:.1f} 秒") + + # 生成梦境总结 + await generate_dream_summary(chat_id, conversation_messages, iteration, cost) + + +def _pick_random_chat_id() -> Optional[str]: + """从 ChatHistory 中随机选择一个 chat_id,用于 dream agent 本次维护 + + 规则: + - 只在 chat_id 所属的 ChatHistory 记录数 >= 10 时才会参与随机选择; + - 记录数不足 10 的 chat_id 将被跳过,不会触发做梦 react。 + """ + try: + # 统计每个 chat_id 的记录数,只保留记录数 >= 10 的 chat_id + rows = ( + ChatHistory.select(ChatHistory.chat_id, fn.COUNT(ChatHistory.id).alias("cnt")) + .group_by(ChatHistory.chat_id) + .having(fn.COUNT(ChatHistory.id) >= 10) + .order_by(ChatHistory.chat_id) + .limit(200) + ) + eligible_ids = [r.chat_id for r in rows] + if not eligible_ids: + logger.warning("[dream] ChatHistory 中暂无满足条件(记录数 >= 10)的 chat_id,本轮 dream 任务跳过。") + return None + chosen = random.choice(eligible_ids) + logger.info(f"[dream] 从 {len(eligible_ids)} 个满足条件的 chat_id 中随机选择:{chosen}") + return chosen + except Exception as e: + logger.error(f"[dream] 随机选择 chat_id 失败: {e}") + return None + + +def _pick_random_memory_for_chat(chat_id: str) -> Optional[int]: + """ + 在给定 chat_id 下随机选择一条 ChatHistory 记录,作为本轮整理的起始记忆。 + """ + try: + rows = ( + ChatHistory.select(ChatHistory.id) + .where(ChatHistory.chat_id == chat_id) + .order_by(ChatHistory.start_time.asc()) + .limit(200) + ) + ids = [r.id for r in rows] + if not ids: + logger.warning(f"[dream] chat_id={chat_id} 下暂无 ChatHistory 记录,无法选择起始记忆。") + return None + return random.choice(ids) + except Exception as e: + logger.error(f"[dream] 在 chat_id={chat_id} 下随机选择起始记忆失败: {e}") + return None + + +async def run_dream_cycle_once() -> None: + """ + 单次 dream 周期: + - 随机选择一个 chat_id + - 在该 chat_id 下随机选择一条 ChatHistory 作为起始记忆 + - 以这条起始记忆为切入点,对该 chat_id 运行一次 dream agent(最多 15 轮) + """ + chat_id = _pick_random_chat_id() + if not chat_id: + return + + start_memory_id = _pick_random_memory_for_chat(chat_id) + await run_dream_agent_once( + chat_id=chat_id, + max_iterations=None, # 使用配置文件中的默认值 + start_memory_id=start_memory_id, + ) + + +async def start_dream_scheduler( + first_delay_seconds: Optional[int] = None, + interval_seconds: Optional[int] = None, + stop_event: Optional[asyncio.Event] = None, +) -> None: + """ + dream 调度器: + - 程序启动后先等待 first_delay_seconds(如果为 None,则使用配置文件中的值,默认 60s) + - 然后每隔 interval_seconds(如果为 None,则使用配置文件中的值,默认 30 分钟)运行一次 dream agent 周期 + - 如果提供 stop_event,则在 stop_event 被 set() 后优雅退出循环 + """ + if first_delay_seconds is None: + first_delay_seconds = global_config.dream.first_delay_seconds + + 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" + ) + + try: + await asyncio.sleep(first_delay_seconds) + while True: + if stop_event is not None and stop_event.is_set(): + logger.info("[dream] 收到停止事件,结束 dream 调度器循环。") + break + + start_ts = time.time() + # 检查当前时间是否在允许做梦的时间段内 + if not global_config.dream.is_in_dream_time(): + logger.debug("[dream] 当前时间不在允许做梦的时间段内,跳过本次执行") + else: + try: + await run_dream_cycle_once() + except Exception as e: + logger.error(f"[dream] 单次 dream 周期执行异常: {e}") + + elapsed = time.time() - start_ts + # 保证两次执行之间至少间隔 interval_seconds + to_sleep = max(0.0, interval_seconds - elapsed) + await asyncio.sleep(to_sleep) + except asyncio.CancelledError: + logger.info("[dream] dream 调度器任务被取消,准备退出。") + raise + + +# 初始化提示词 +init_dream_prompts() + diff --git a/src/dream/dream_generator.py b/src/dream/dream_generator.py new file mode 100644 index 00000000..174d1b69 --- /dev/null +++ b/src/dream/dream_generator.py @@ -0,0 +1,198 @@ +import random +from typing import List, Optional + +from src.common.logger import get_logger +from src.config.config import model_config +from src.chat.utils.prompt_builder import Prompt +from src.llm_models.payload_content.message import RoleType, Message +from src.llm_models.utils_model import LLMRequest + +logger = get_logger("dream_generator") + +# 初始化 utils 模型用于生成梦境总结 +_dream_summary_model: Optional[LLMRequest] = None + +# 梦境风格列表(21种) +DREAM_STYLES = [ + "保持诗意和想象力,自由编写", + "诗意朦胧,如薄雾笼罩的清晨", + "奇幻冒险,充满未知与探索", + "温暖怀旧,带着时光的痕迹", + "神秘悬疑,暗藏深意", + "浪漫唯美,如诗如画", + "科幻未来,科技与想象交织", + "自然清新,如山林间的微风", + "深沉哲思,引人深思", + "轻松幽默,充满趣味", + "悲伤忧郁,带着淡淡哀愁", + "激昂热烈,充满活力", + "宁静平和,如湖面般平静", + "荒诞离奇,打破常规", + "细腻温柔,如春风拂面", + "壮阔宏大,气势磅礴", + "简约纯粹,返璞归真", + "复杂多变,层次丰富", + "梦幻迷离,虚实难辨", + "现实写意,贴近生活", + "抽象概念,超越具象", +] + + +def get_random_dream_styles(count: int = 2) -> List[str]: + """从梦境风格列表中随机选择指定数量的风格""" + return random.sample(DREAM_STYLES, min(count, len(DREAM_STYLES))) + + +def get_dream_summary_model() -> LLMRequest: + """获取用于生成梦境总结的 utils 模型实例""" + global _dream_summary_model + if _dream_summary_model is None: + _dream_summary_model = LLMRequest( + model_set=model_config.model_task_config.utils, + request_type="dream.summary", + ) + return _dream_summary_model + + +def init_dream_summary_prompt() -> None: + """初始化梦境总结的提示词""" + Prompt( + """ +你刚刚完成了一次对聊天记录的记忆整理工作。以下是整理过程的摘要: +整理过程: +{conversation_text} + +请将这次整理涉及的相关信息改写为一个富有诗意和想象力的"梦境",请你仅使用具体的记忆的内容,而不是整理过程编写。 +要求: +1. 使用第一人称视角 +2. 叙述直白,不要复杂修辞,口语化 +3. 长度控制在200-800字 +4. 用中文输出 +梦境风格: +{dream_styles} +请直接输出梦境内容,不要添加其他说明: +""", + name="dream_summary_prompt", + ) + + +async def generate_dream_summary( + chat_id: str, + conversation_messages: List[Message], + total_iterations: int, + time_cost: float, +) -> None: + """生成梦境总结并输出到日志""" + 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: + if msg.role == RoleType.Tool and msg.tool_call_id: + content = "" + if msg.content: + if isinstance(msg.content, list) and msg.content: + content = msg.content[0].text if hasattr(msg.content[0], "text") else str(msg.content[0]) + 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 + # 提取思考内容 + 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]) + 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 ''}") + + # 记录每个工具调用的详细信息 + 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: + role = msg.role.value if hasattr(msg.role, "value") else str(msg.role) + 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: + # 截取前500字符,避免过长 + content_preview = content[:500] + ("..." if len(content) > 500 else "") + conversation_summary.append(f"[{role}] {content_preview}") + elif role == "tool": + # 工具结果,只保留关键信息 + if content: + # 截取前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)]) + + # 使用 Prompt 管理器格式化梦境生成 prompt + dream_prompt = await global_prompt_manager.format_prompt( + "dream_summary_prompt", + chat_id=chat_id, + total_iterations=total_iterations, + time_cost=time_cost, + conversation_text=conversation_text, + dream_styles=dream_styles_text, + ) + + # 调用 utils 模型生成梦境 + summary_model = get_dream_summary_model() + dream_content, (reasoning, model_name, _) = await summary_model.generate_response_async( + dream_prompt, + 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 diff --git a/src/dream/tools/__init__.py b/src/dream/tools/__init__.py new file mode 100644 index 00000000..488675a6 --- /dev/null +++ b/src/dream/tools/__init__.py @@ -0,0 +1,10 @@ +""" +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 new file mode 100644 index 00000000..43535c29 --- /dev/null +++ b/src/dream/tools/create_chat_history_tool.py @@ -0,0 +1,66 @@ +import time + +from src.common.logger import get_logger +from src.common.database.database_model import ChatHistory + +logger = get_logger("dream_agent") + + +def make_create_chat_history(chat_id: str): + async def create_chat_history( + theme: str, + summary: str, + keywords: str, + key_point: str, + start_time: float, + end_time: float, + ) -> str: + """创建一条新的 ChatHistory 概括记录(用于整理/合并后的新记忆)""" + try: + logger.info( + f"[dream][tool] 调用 create_chat_history(" + f"theme={bool(theme)}, summary={bool(summary)}, " + f"keywords={bool(keywords)}, key_point={bool(key_point)}, " + f"start_time={start_time}, end_time={end_time}) (chat_id={chat_id})" + ) + + now_ts = time.time() + + # 将传入的 start_time/end_time(如果有)解析为时间戳;否则回退为当前时间 + def _parse_ts(value, default): + if value is None: + return default + try: + return float(value) + except (TypeError, ValueError): + return default + + start_ts = _parse_ts(start_time, now_ts) + end_ts = _parse_ts(end_time, now_ts) + + record = ChatHistory.create( + chat_id=chat_id, + theme=theme, + summary=summary, + keywords=keywords, + key_point=key_point, + # 对于由 dream 整理产生的新概括,时间范围优先使用工具提供的时间,否则使用当前时间占位 + start_time=start_ts, + end_time=end_ts, + ) + + msg = ( + f"已创建新的 ChatHistory 记录,ID={record.id}," + f"theme={record.theme or '无'},summary={'有' if record.summary else '无'}。" + ) + logger.info(f"[dream][tool] create_chat_history 完成: {msg}") + return msg + except Exception as e: + logger.error(f"create_chat_history 失败: {e}") + 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 new file mode 100644 index 00000000..02cedf94 --- /dev/null +++ b/src/dream/tools/delete_chat_history_tool.py @@ -0,0 +1,29 @@ +from src.common.logger import get_logger +from src.common.database.database_model import ChatHistory + +logger = get_logger("dream_agent") + + +def make_delete_chat_history(chat_id: str): # chat_id 目前未直接使用,预留以备扩展 + async def delete_chat_history(memory_id: int) -> str: + """删除一条 chat_history 记录""" + try: + logger.info(f"[dream][tool] 调用 delete_chat_history(memory_id={memory_id})") + record = ChatHistory.get_or_none(ChatHistory.id == memory_id) + if not record: + msg = f"未找到 ID={memory_id} 的 ChatHistory 记录,无法删除。" + logger.info(f"[dream][tool] delete_chat_history 未找到记录: {msg}") + return msg + rows = ChatHistory.delete().where(ChatHistory.id == memory_id).execute() + msg = f"已删除 ID={memory_id} 的 ChatHistory 记录,受影响行数={rows}。" + logger.info(f"[dream][tool] delete_chat_history 完成: {msg}") + return msg + except Exception as e: + logger.error(f"delete_chat_history 失败: {e}") + 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 new file mode 100644 index 00000000..2cf38e56 --- /dev/null +++ b/src/dream/tools/delete_jargon_tool.py @@ -0,0 +1,29 @@ +from src.common.logger import get_logger +from src.common.database.database_model import Jargon + +logger = get_logger("dream_agent") + + +def make_delete_jargon(chat_id: str): # chat_id 目前未直接使用,预留以备扩展 + async def delete_jargon(jargon_id: int) -> str: + """删除一条 Jargon 记录""" + try: + logger.info(f"[dream][tool] 调用 delete_jargon(jargon_id={jargon_id})") + record = Jargon.get_or_none(Jargon.id == jargon_id) + if not record: + msg = f"未找到 ID={jargon_id} 的 Jargon 记录,无法删除。" + logger.info(f"[dream][tool] delete_jargon 未找到记录: {msg}") + return msg + rows = Jargon.delete().where(Jargon.id == jargon_id).execute() + msg = f"已删除 ID={jargon_id} 的 Jargon 记录(内容:{record.content}),受影响行数={rows}。" + logger.info(f"[dream][tool] delete_jargon 完成: {msg}") + return msg + except Exception as e: + logger.error(f"delete_jargon 失败: {e}") + 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 new file mode 100644 index 00000000..dbb9f15f --- /dev/null +++ b/src/dream/tools/finish_maintenance_tool.py @@ -0,0 +1,20 @@ +from typing import Optional + +from src.common.logger import get_logger + +logger = get_logger("dream_agent") + + +def make_finish_maintenance(chat_id: str): # chat_id 目前未直接使用,预留以备扩展 + async def finish_maintenance(reason: Optional[str] = None) -> str: + """结束本次 dream 维护任务。当你认为当前 chat_id 下的维护工作已经完成,没有更多需要整理的内容时,调用此工具来结束本次运行。""" + reason_text = f",原因:{reason}" if reason else "" + msg = f"DREAM_MAINTENANCE_COMPLETE{reason_text}" + logger.info(f"[dream][tool] 调用 finish_maintenance,结束本次维护{reason_text}") + 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 new file mode 100644 index 00000000..b8b0da54 --- /dev/null +++ b/src/dream/tools/get_chat_history_detail_tool.py @@ -0,0 +1,55 @@ +import time +from typing import Optional + +from src.common.logger import get_logger +from src.common.database.database_model import ChatHistory + +logger = get_logger("dream_agent") + + +def make_get_chat_history_detail(chat_id: str): # chat_id 目前未直接使用,预留以备扩展 + async def get_chat_history_detail(memory_id: int) -> str: + """获取单条 chat_history 的完整内容""" + try: + logger.info(f"[dream][tool] 调用 get_chat_history_detail(memory_id={memory_id})") + record = ChatHistory.get_or_none(ChatHistory.id == memory_id) + if not record: + msg = f"未找到 ID={memory_id} 的 ChatHistory 记录。" + logger.info(f"[dream][tool] get_chat_history_detail 未找到记录: {msg}") + return msg + + # 将时间戳转换为可读时间格式 + start_time_str = ( + 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 "未知" + ) + + result = ( + f"ID={record.id}\n" + # f"chat_id={record.chat_id}\n" + f"时间范围={start_time_str} 至 {end_time_str}\n" + f"主题={record.theme or '无'}\n" + f"关键词={record.keywords or '无'}\n" + f"参与者={record.participants or '无'}\n" + f"概括={record.summary or '无'}\n" + f"关键信息={record.key_point or '无'}" + ) + 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 new file mode 100644 index 00000000..0c7d1da6 --- /dev/null +++ b/src/dream/tools/search_chat_history_tool.py @@ -0,0 +1,226 @@ +import json +from typing import List, Optional + +from src.common.logger import get_logger +from src.common.database.database_model import ChatHistory +from src.chat.utils.utils import parse_keywords_string + +logger = get_logger("dream_agent") + + +def make_search_chat_history(chat_id: str): + async def search_chat_history( + keyword: Optional[str] = None, + participant: Optional[str] = None, + ) -> str: + """根据关键词或参与人查询记忆,返回匹配的记忆id、记忆标题theme和关键词keywords(dream 维护专用版本)""" + try: + # 检查参数 + if not keyword and not participant: + return "未指定查询参数(需要提供keyword或participant之一)" + + logger.info( + f"[dream][tool] 调用 search_chat_history(keyword={keyword}, participant={participant}) " + f"(作用域 chat_id={chat_id})" + ) + + # 构建查询条件 + query = ChatHistory.select().where(ChatHistory.chat_id == chat_id) + + # 执行查询(按时间倒序,最近的在前) + records = list(query.order_by(ChatHistory.start_time.desc()).limit(50)) + + filtered_records: List[ChatHistory] = [] + + for record in records: + participant_matched = True # 如果没有participant条件,默认为True + keyword_matched = True # 如果没有keyword条件,默认为True + + # 检查参与人匹配 + if participant: + participant_matched = False + participants_list: List[str] = [] + if record.participants: + try: + participants_data = ( + json.loads(record.participants) + if isinstance(record.participants, str) + else record.participants + ) + if isinstance(participants_data, list): + participants_list = [str(p).lower() for p in participants_data] + except (json.JSONDecodeError, TypeError, ValueError): + pass + + participant_lower = participant.lower().strip() + if participant_lower and any(participant_lower in p for p in participants_list): + participant_matched = True + + # 检查关键词匹配 + if keyword: + keyword_matched = False + # 解析多个关键词(支持空格、逗号等分隔符) + keywords_list = parse_keywords_string(keyword) + if not keywords_list: + keywords_list = [keyword.strip()] if keyword.strip() else [] + + # 转换为小写以便匹配 + keywords_lower = [kw.lower() for kw in keywords_list if kw.strip()] + + if keywords_lower: + # 在theme、keywords、summary、original_text中搜索 + theme = (record.theme or "").lower() + summary = (record.summary or "").lower() + original_text = (record.original_text or "").lower() + + # 解析record中的keywords JSON + record_keywords_list: List[str] = [] + if record.keywords: + try: + keywords_data = ( + 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] + except (json.JSONDecodeError, TypeError, ValueError): + pass + + # 有容错的全匹配:如果关键词数量>2,允许n-1个关键词匹配;否则必须全部匹配 + matched_count = 0 + for kw in keywords_lower: + kw_matched = ( + kw in theme + or kw in summary + or kw in original_text + or any(kw in k for k in record_keywords_list) + ) + if kw_matched: + matched_count += 1 + + # 计算需要匹配的关键词数量 + total_keywords = len(keywords_lower) + if total_keywords > 2: + # 关键词数量>2,允许n-1个关键词匹配 + required_matches = total_keywords - 1 + else: + # 关键词数量<=2,必须全部匹配 + required_matches = total_keywords + + keyword_matched = matched_count >= required_matches + + # 两者都匹配(如果同时有participant和keyword,需要两者都匹配;如果只有一个条件,只需要该条件匹配) + matched = participant_matched and keyword_matched + + if matched: + filtered_records.append(record) + + if not filtered_records: + if keyword and participant: + keywords_str = "、".join(parse_keywords_string(keyword) if keyword else []) + return f"未找到包含关键词'{keywords_str}'且参与人包含'{participant}'的聊天记录" + elif keyword: + keywords_list = parse_keywords_string(keyword) + 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}'的聊天记录" + ) + else: + return f"未找到包含所有关键词'{keywords_str}'的聊天记录" + elif participant: + return f"未找到参与人包含'{participant}'的聊天记录" + else: + return "未找到相关聊天记录" + + # 如果匹配结果超过20条,不返回具体记录,只返回提示和所有相关关键词 + if len(filtered_records) > 20: + all_keywords_set = set() + for record in filtered_records: + if record.keywords: + try: + keywords_data = ( + json.loads(record.keywords) + if isinstance(record.keywords, str) + else record.keywords + ) + if isinstance(keywords_data, list): + for k in keywords_data: + k_str = str(k).strip() + if k_str: + all_keywords_set.add(k_str) + except (json.JSONDecodeError, TypeError, ValueError): + continue + + search_label = keyword or participant or "当前条件" + + if all_keywords_set: + keywords_str = "、".join(sorted(all_keywords_set)) + response_text = ( + f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" + f"有关\"{search_label}\"的关键词:\n" + f"{keywords_str}" + ) + else: + response_text = ( + f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" + f"有关\"{search_label}\"的关键词信息为空" + ) + + logger.info( + f"[dream][tool] search_chat_history 匹配结果超过20条,返回关键词汇总提示,总数={len(filtered_records)}" + ) + return response_text + + # 构建结果文本,返回id、theme和keywords(最多20条) + results: List[str] = [] + for record in filtered_records[:20]: + result_parts: List[str] = [] + + # 记忆ID + result_parts.append(f"记忆ID:{record.id}") + + # 主题 + if record.theme: + result_parts.append(f"主题:{record.theme}") + else: + result_parts.append("主题:(无)") + + # 关键词 + if record.keywords: + try: + keywords_data = ( + 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]) + result_parts.append(f"关键词:{keywords_str}") + else: + result_parts.append("关键词:(无)") + except (json.JSONDecodeError, TypeError, ValueError): + result_parts.append("关键词:(无)") + else: + result_parts.append("关键词:(无)") + + results.append("\n".join(result_parts)) + + if not results: + return "未找到相关聊天记录" + + response_text = "\n\n---\n\n".join(results) + + logger.info(f"[dream][tool] search_chat_history 返回 {len(filtered_records)} 条匹配记录") + return response_text + except Exception as e: + logger.error(f"search_chat_history 失败: {e}") + 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 new file mode 100644 index 00000000..d20f170b --- /dev/null +++ b/src/dream/tools/search_jargon_tool.py @@ -0,0 +1,106 @@ +from typing import List + +from src.common.logger import get_logger +from src.common.database.database_model import Jargon +from src.config.config import global_config +from src.chat.utils.utils import parse_keywords_string +from src.jargon.jargon_utils import parse_chat_id_list, chat_id_list_contains + +logger = get_logger("dream_agent") + + +def make_search_jargon(chat_id: str): + async def search_jargon(keyword: str) -> str: + """根据一个或多个关键词搜索当前 chat_id 相关的 Jargon 记录概览(只包含 is_jargon=True,是否跨 chat_id 由 all_global 决定)""" + try: + if not keyword or not keyword.strip(): + return "未指定查询关键词(参数 keyword 为必填,且不能为空)" + + logger.info( + f"[dream][tool] 调用 search_jargon(keyword={keyword}) (作用域 chat_id={chat_id})" + ) + + # 基础条件:只查 is_jargon=True 的记录 + query = Jargon.select().where(Jargon.is_jargon) + + # 根据 all_global 配置决定 chat_id 作用域 + if global_config.jargon.all_global: + # 开启全局黑话:只看 is_global=True 的记录,不区分 chat_id + query = query.where(Jargon.is_global) + else: + # 关闭全局黑话:后续在 Python 层按 chat_id 列表过滤(包含 is_global=True) + pass + + # 先按使用次数排序取一批候选,做一个安全上限 + query = query.order_by(Jargon.count.desc()).limit(200) + candidates = list(query) + + if not candidates: + msg = "未找到符合条件的 Jargon 记录。" + logger.info(f"[dream][tool] search_jargon 无记录: {msg}") + return msg + + # 关键词为必填,因此此处必然执行关键词过滤(支持多个关键词,大小写不敏感) + keywords_list = parse_keywords_string(keyword) or [] + if not keywords_list and keyword.strip(): + keywords_list = [keyword.strip()] + keywords_lower = [kw.lower() for kw in keywords_list if kw.strip()] + + # 先按关键词过滤(仅对 content 字段进行匹配) + filtered_keyword: List[Jargon] = [] + for r in candidates: + content = (r.content or "").lower() + + # 只要命中任意一个关键词即可视为匹配(OR 逻辑) + any_matched = False + for kw in keywords_lower: + if not kw: + continue + if kw in content: + any_matched = True + break + + if any_matched: + filtered_keyword.append(r) + + if global_config.jargon.all_global: + # 全局黑话模式:不再做 chat_id 过滤,直接使用关键词过滤结果 + records = filtered_keyword + else: + # 非全局模式:仅保留全局黑话或 chat_id 列表中包含当前 chat_id 的记录 + records = [] + for r in filtered_keyword: + if r.is_global: + records.append(r) + continue + chat_id_list = parse_chat_id_list(r.chat_id) + if chat_id_list_contains(chat_id_list, chat_id): + records.append(r) + + if not records: + scope_note = ( + "(当前为全局黑话模式,仅统计 is_global=True 的条目)" + if global_config.jargon.all_global + else "(当前为按 chat_id 作用域模式,仅统计全局黑话或与当前 chat_id 相关的条目)" + ) + return f"未找到包含关键词'{keyword}'的 Jargon 记录{scope_note}" + + lines: List[str] = [] + for r in records: + is_jargon_str = "是" if r.is_jargon else "否" if r.is_jargon is False else "未判定" + is_global_str = "全局" if r.is_global else "非全局" + lines.append( + f"ID={r.id} | 内容={r.content} | 含义={r.meaning or '无'} | " + f"chat_id={r.chat_id} | {is_global_str} | 是否黑话={is_jargon_str}" + ) + + result = "\n".join(lines) + logger.info(f"[dream][tool] search_jargon 返回 {len(records)} 条记录") + return result + except Exception as e: + logger.error(f"search_jargon 失败: {e}") + 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 new file mode 100644 index 00000000..2070facf --- /dev/null +++ b/src/dream/tools/update_chat_history_tool.py @@ -0,0 +1,55 @@ +from typing import Any, Dict, Optional + +from src.common.logger import get_logger +from src.common.database.database_model import ChatHistory +from src.plugin_system.apis import database_api + +logger = get_logger("dream_agent") + + +def make_update_chat_history(chat_id: str): # chat_id 目前未直接使用,预留以备扩展 + async def update_chat_history( + memory_id: int, + theme: Optional[str] = None, + summary: Optional[str] = None, + keywords: Optional[str] = None, + key_point: Optional[str] = None, + ) -> str: + """按字段更新 chat_history(字符串字段要求 JSON 的字段须传入已序列化的字符串)""" + try: + logger.info( + f"[dream][tool] 调用 update_chat_history(memory_id={memory_id}, " + f"theme={bool(theme)}, summary={bool(summary)}, keywords={bool(keywords)}, key_point={bool(key_point)})" + ) + record = ChatHistory.get_or_none(ChatHistory.id == memory_id) + if not record: + msg = f"未找到 ID={memory_id} 的 ChatHistory 记录,无法更新。" + logger.info(f"[dream][tool] update_chat_history 未找到记录: {msg}") + return msg + + data: Dict[str, Any] = {} + if theme is not None: + data["theme"] = theme + if summary is not None: + data["summary"] = summary + if keywords is not None: + data["keywords"] = keywords + if key_point is not None: + data["key_point"] = key_point + + if not data: + return "未提供任何需要更新的字段。" + + await database_api.db_save(ChatHistory, data=data, key_field="id", key_value=memory_id) + msg = f"已更新 ChatHistory 记录 ID={memory_id},更新字段={list(data.keys())}。" + logger.info(f"[dream][tool] update_chat_history 完成: {msg}") + return msg + except Exception as e: + logger.error(f"update_chat_history 失败: {e}") + 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 new file mode 100644 index 00000000..9ebfe7b9 --- /dev/null +++ b/src/dream/tools/update_jargon_tool.py @@ -0,0 +1,55 @@ +from typing import Any, Dict, Optional + +from src.common.logger import get_logger +from src.common.database.database_model import Jargon +from src.plugin_system.apis import database_api + +logger = get_logger("dream_agent") + + +def make_update_jargon(chat_id: str): # chat_id 目前未直接使用,预留以备扩展 + async def update_jargon( + jargon_id: int, + meaning: Optional[str] = None, + is_global: Optional[bool] = None, + is_jargon: Optional[bool] = None, + content: Optional[str] = None, + ) -> str: + """按字段更新 Jargon 记录,可用于修正含义、调整全局性、标记是否为黑话等""" + try: + logger.info( + f"[dream][tool] 调用 update_jargon(jargon_id={jargon_id}, " + f"meaning={bool(meaning)}, is_global={is_global}, is_jargon={is_jargon}, content={bool(content)})" + ) + record = Jargon.get_or_none(Jargon.id == jargon_id) + if not record: + msg = f"未找到 ID={jargon_id} 的 Jargon 记录,无法更新。" + logger.info(f"[dream][tool] update_jargon 未找到记录: {msg}") + return msg + + data: Dict[str, Any] = {} + if meaning is not None: + data["meaning"] = meaning + if is_global is not None: + data["is_global"] = is_global + if is_jargon is not None: + data["is_jargon"] = is_jargon + if content is not None: + data["content"] = content + + if not data: + return "未提供任何需要更新的字段。" + + await database_api.db_save(Jargon, data=data, key_field="id", key_value=jargon_id) + msg = f"已更新 Jargon 记录 ID={jargon_id},更新字段={list(data.keys())}。" + logger.info(f"[dream][tool] update_jargon 完成: {msg}") + return msg + except Exception as e: + logger.error(f"update_jargon 失败: {e}") + return f"update_jargon 执行失败: {e}" + + return update_jargon + + + + diff --git a/src/express/expression_learner.py b/src/express/expression_learner.py index af69cad6..e39677a9 100644 --- a/src/express/expression_learner.py +++ b/src/express/expression_learner.py @@ -12,11 +12,10 @@ from src.config.config import model_config, global_config from src.chat.utils.chat_message_builder import ( get_raw_msg_by_timestamp_with_chat_inclusive, build_anonymous_messages, - build_bare_messages, ) from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.chat.message_receive.chat_stream import get_chat_manager -from src.express.express_utils import filter_message_content, calculate_similarity +from src.express.express_utils import filter_message_content from json_repair import repair_json @@ -26,10 +25,10 @@ logger = get_logger("expressor") def init_prompt() -> None: - learn_style_prompt = """ -{chat_str} + learn_style_prompt = """{chat_str} -请从上面这段群聊中概括除了人名为"SELF"之外的人的语言风格 +请从上面这段群聊中概括除了人名为"SELF"之外的人的语言风格。 +每一行消息前面的方括号中的数字(如 [1]、[2])是该行消息的唯一编号,请在输出中引用这些编号来标注“表达方式的来源行”。 1. 只考虑文字,不要考虑表情包和图片 2. 不要涉及具体的人名,但是可以涉及具体名词 3. 思考有没有特殊的梗,一并总结成语言风格 @@ -37,41 +36,29 @@ def init_prompt() -> None: 注意:总结成如下格式的规律,总结的内容要详细,但具有概括性: 例如:当"AAAAA"时,可以"BBBBB", AAAAA代表某个具体的场景,不超过20个字。BBBBB代表对应的语言风格,特定句式或表达方式,不超过20个字。 -例如: -当"对某件事表示十分惊叹"时,使用"我嘞个xxxx" -当"表示讽刺的赞同,不讲道理"时,使用"对对对" -当"想说明某个具体的事实观点,但懒得明说,使用"懂的都懂" -当"当涉及游戏相关时,夸赞,略带戏谑意味"时,使用"这么强!" +请严格以 JSON 数组的形式输出结果,每个元素为一个对象,结构如下(注意字段名): +[ + {{"situation": "AAAAA", "style": "BBBBB", "source_id": "3"}}, + {{"situation": "CCCC", "style": "DDDD", "source_id": "7"}} + {{"situation": "对某件事表示十分惊叹", "style": "使用 我嘞个xxxx", "source_id": "[消息编号]"}}, + {{"situation": "表示讽刺的赞同,不讲道理", "style": "对对对", "source_id": "[消息编号]"}}, + {{"situation": "当涉及游戏相关时,夸赞,略带戏谑意味", "style": "使用 这么强!", "source_id": "[消息编号]"}}, +] -请注意:不要总结你自己(SELF)的发言,尽量保证总结内容的逻辑性 -现在请你概括 +请注意: +- 不要总结你自己(SELF)的发言,尽量保证总结内容的逻辑性 +- 请只针对最重要的若干条表达方式进行总结,避免输出太多重复或相似的条目 + +其中: +- situation:表示“在什么情境下”的简短概括(不超过20个字) +- style:表示对应的语言风格或常用表达(不超过20个字) +- source_id:该表达方式对应的“来源行编号”,即上方聊天记录中方括号里的数字(例如 [3]),请只输出数字本身,不要包含方括号 + +现在请你输出 JSON: """ Prompt(learn_style_prompt, "learn_style_prompt") - match_expression_context_prompt = """ -**聊天内容** -{chat_str} -**从聊天内容总结的表达方式pairs** -{expression_pairs} - -请你为上面的每一条表达方式,找到该表达方式的原文句子,并输出匹配结果,expression_pair不能有重复,每个expression_pair仅输出一个最合适的context。 -如果找不到原句,就不输出该句的匹配结果。 -以json格式输出: -格式如下: -{{ - "expression_pair": "表达方式pair的序号(数字)", - "context": "与表达方式对应的原文句子的原始内容,不要修改原文句子的内容", -}}, -{{ - "expression_pair": "表达方式pair的序号(数字)", - "context": "与表达方式对应的原文句子的原始内容,不要修改原文句子的内容", -}}, -... - -现在请你输出匹配结果: -""" - Prompt(match_expression_context_prompt, "match_expression_context_prompt") class ExpressionLearner: @@ -99,6 +86,10 @@ class ExpressionLearner: _, self.enable_learning, self.learning_intensity = global_config.expression.get_expression_config_for_chat( self.chat_id ) + # 防止除以零:如果学习强度为0或负数,使用最小值0.0001 + if self.learning_intensity <= 0: + logger.warning(f"学习强度为 {self.learning_intensity},已自动调整为 0.0001 以避免除以零错误") + self.learning_intensity = 0.0000001 self.min_messages_for_learning = 15 / self.learning_intensity # 触发学习所需的最少消息数 self.min_learning_interval = 120 / self.learning_intensity @@ -193,7 +184,6 @@ class ExpressionLearner: situation, style, _context, - _up_content, ) in learnt_expressions: learnt_expressions_str += f"{situation}->{style}\n" logger.info(f"在 {self.chat_name} 学习到表达风格:\n{learnt_expressions_str}") @@ -205,193 +195,17 @@ class ExpressionLearner: situation, style, context, - up_content, ) in learnt_expressions: await self._upsert_expression_record( situation=situation, style=style, context=context, - up_content=up_content, current_time=current_time, ) return learnt_expressions - async def match_expression_context( - self, expression_pairs: List[Tuple[str, str]], random_msg_match_str: str - ) -> List[Tuple[str, str, str]]: - # 为expression_pairs逐个条目赋予编号,并构建成字符串 - numbered_pairs = [] - for i, (situation, style) in enumerate(expression_pairs, 1): - numbered_pairs.append(f'{i}. 当"{situation}"时,使用"{style}"') - - expression_pairs_str = "\n".join(numbered_pairs) - - prompt = "match_expression_context_prompt" - prompt = await global_prompt_manager.format_prompt( - prompt, - expression_pairs=expression_pairs_str, - chat_str=random_msg_match_str, - ) - - response, _ = await self.express_learn_model.generate_response_async(prompt, temperature=0.3) - - # print(f"match_expression_context_prompt: {prompt}") - # print(f"{response}") - - # 解析JSON响应 - match_responses = [] - try: - response = response.strip() - - # 尝试提取JSON代码块(如果存在) - json_pattern = r"```json\s*(.*?)\s*```" - matches = re.findall(json_pattern, response, re.DOTALL) - if matches: - response = matches[0].strip() - - # 移除可能的markdown代码块标记(如果没有找到```json,但可能有```) - if not matches: - response = re.sub(r"^```\s*", "", response, flags=re.MULTILINE) - response = re.sub(r"```\s*$", "", response, flags=re.MULTILINE) - response = response.strip() - - # 检查是否已经是标准JSON数组格式 - if response.startswith("[") and response.endswith("]"): - match_responses = json.loads(response) - else: - # 尝试直接解析多个JSON对象 - try: - # 如果是多个JSON对象用逗号分隔,包装成数组 - if response.startswith("{") and not response.startswith("["): - response = "[" + response + "]" - match_responses = json.loads(response) - else: - # 使用repair_json处理响应 - repaired_content = repair_json(response) - - # 确保repaired_content是列表格式 - if isinstance(repaired_content, str): - try: - parsed_data = json.loads(repaired_content) - if isinstance(parsed_data, dict): - # 如果是字典,包装成列表 - match_responses = [parsed_data] - elif isinstance(parsed_data, list): - match_responses = parsed_data - else: - match_responses = [] - except json.JSONDecodeError: - match_responses = [] - elif isinstance(repaired_content, dict): - # 如果是字典,包装成列表 - match_responses = [repaired_content] - elif isinstance(repaired_content, list): - match_responses = repaired_content - else: - match_responses = [] - except json.JSONDecodeError: - # 如果还是失败,尝试repair_json - repaired_content = repair_json(response) - if isinstance(repaired_content, str): - parsed_data = json.loads(repaired_content) - match_responses = parsed_data if isinstance(parsed_data, list) else [parsed_data] - else: - match_responses = repaired_content if isinstance(repaired_content, list) else [repaired_content] - - except (json.JSONDecodeError, Exception) as e: - logger.error(f"解析匹配响应JSON失败: {e}, 响应内容: \n{response}") - return [] - - # 确保 match_responses 是一个列表 - if not isinstance(match_responses, list): - if isinstance(match_responses, dict): - match_responses = [match_responses] - else: - logger.error(f"match_responses 不是列表或字典类型: {type(match_responses)}, 内容: {match_responses}") - return [] - - # 清理和规范化 match_responses 中的元素 - normalized_responses = [] - for item in match_responses: - if isinstance(item, dict): - # 已经是字典,直接添加 - normalized_responses.append(item) - elif isinstance(item, str): - # 如果是字符串,尝试解析为 JSON - try: - parsed = json.loads(item) - if isinstance(parsed, dict): - normalized_responses.append(parsed) - elif isinstance(parsed, list): - # 如果是列表,递归处理 - for sub_item in parsed: - if isinstance(sub_item, dict): - normalized_responses.append(sub_item) - else: - logger.debug(f"跳过非字典类型的子元素: {type(sub_item)}, 内容: {sub_item}") - else: - logger.debug(f"跳过无法转换为字典的字符串元素: {item}") - except (json.JSONDecodeError, TypeError): - logger.debug(f"跳过无法解析为JSON的字符串元素: {item}") - elif isinstance(item, list): - # 如果是列表,展开并处理其中的字典 - for sub_item in item: - if isinstance(sub_item, dict): - normalized_responses.append(sub_item) - elif isinstance(sub_item, str): - # 尝试解析字符串 - try: - parsed = json.loads(sub_item) - if isinstance(parsed, dict): - normalized_responses.append(parsed) - else: - logger.debug(f"跳过非字典类型的解析结果: {type(parsed)}, 内容: {parsed}") - except (json.JSONDecodeError, TypeError): - logger.debug(f"跳过无法解析为JSON的字符串子元素: {sub_item}") - else: - logger.debug(f"跳过非字典类型的列表元素: {type(sub_item)}, 内容: {sub_item}") - else: - logger.debug(f"跳过无法处理的元素类型: {type(item)}, 内容: {item}") - - match_responses = normalized_responses - - matched_expressions = [] - used_pair_indices = set() # 用于跟踪已经使用的expression_pair索引 - - logger.debug(f"规范化后的 match_responses 类型: {type(match_responses)}, 长度: {len(match_responses)}") - logger.debug(f"规范化后的 match_responses 内容: {match_responses}") - - for match_response in match_responses: - try: - # 检查 match_response 的类型(此时应该都是字典) - if not isinstance(match_response, dict): - logger.error(f"match_response 不是字典类型: {type(match_response)}, 内容: {match_response}") - continue - - # 获取表达方式序号 - if "expression_pair" not in match_response: - logger.error(f"match_response 缺少 'expression_pair' 字段: {match_response}") - continue - - pair_index = int(match_response["expression_pair"]) - 1 # 转换为0-based索引 - - # 检查索引是否有效且未被使用过 - if 0 <= pair_index < len(expression_pairs) and pair_index not in used_pair_indices: - situation, style = expression_pairs[pair_index] - context = match_response.get("context", "") - matched_expressions.append((situation, style, context)) - used_pair_indices.add(pair_index) # 标记该索引已使用 - logger.debug(f"成功匹配表达方式 {pair_index + 1}: {situation} -> {style}") - elif pair_index in used_pair_indices: - logger.debug(f"跳过重复的表达方式 {pair_index + 1}") - except (ValueError, KeyError, IndexError, TypeError) as e: - logger.error(f"解析匹配条目失败: {e}, 条目: {match_response}") - continue - - return matched_expressions - - async def learn_expression(self, num: int = 10, timestamp_start: Optional[float] = None) -> Optional[List[Tuple[str, str, str, str]]]: + async def learn_expression(self, num: int = 10, timestamp_start: Optional[float] = None) -> Optional[List[Tuple[str, str, str]]]: """从指定聊天流学习表达方式 Args: @@ -414,10 +228,8 @@ class ExpressionLearner: if not random_msg or random_msg == []: return None - # 学习用 - random_msg_str: str = await build_anonymous_messages(random_msg) - # 溯源用 - random_msg_match_str: str = await build_bare_messages(random_msg) + # 学习用(开启行编号,便于溯源) + random_msg_str: str = await build_anonymous_messages(random_msg, show_ids=True) prompt: str = await global_prompt_manager.format_prompt( "learn_style_prompt", @@ -432,83 +244,107 @@ class ExpressionLearner: except Exception as e: logger.error(f"学习表达方式失败,模型生成出错: {e}") return None - expressions: List[Tuple[str, str]] = self.parse_expression_response(response) + + # 解析 LLM 返回的表达方式列表(包含来源行编号) + expressions: List[Tuple[str, str, str]] = self.parse_expression_response(response) expressions = self._filter_self_reference_styles(expressions) if not expressions: logger.info("过滤后没有可用的表达方式(style 与机器人名称重复)") return None # logger.debug(f"学习{type_str}的response: {response}") - # 对表达方式溯源 - matched_expressions: List[Tuple[str, str, str]] = await self.match_expression_context( - expressions, random_msg_match_str - ) - # 为每条消息构建精简文本列表,保留到原消息索引的映射 - bare_lines: List[Tuple[int, str]] = self._build_bare_lines(random_msg) - # 将 matched_expressions 结合上一句 up_content(若不存在上一句则跳过) - filtered_with_up: List[Tuple[str, str, str, str]] = [] # (situation, style, context, up_content) - for situation, style, context in matched_expressions: - # 在 bare_lines 中找到第一处相似度达到85%的行 - pos = None - for i, (_, c) in enumerate(bare_lines): - similarity = calculate_similarity(c, context) - if similarity >= 0.85: # 85%相似度阈值 - pos = i - break + # 直接根据 source_id 在 random_msg 中溯源,获取 context + filtered_expressions: List[Tuple[str, str, str]] = [] # (situation, style, context) - if pos is None or pos == 0: - # 没有匹配到目标句或没有上一句,跳过该表达 + for situation, style, source_id in expressions: + source_id_str = (source_id or "").strip() + if not source_id_str.isdigit(): + # 无效的来源行编号,跳过 continue - # 检查目标句是否为空 - target_content = bare_lines[pos][1] - if not target_content: - # 目标句为空,跳过该表达 + line_index = int(source_id_str) - 1 # build_anonymous_messages 的编号从 1 开始 + if line_index < 0 or line_index >= len(random_msg): + # 超出范围,跳过 continue - prev_original_idx = bare_lines[pos - 1][0] - up_content = filter_message_content(random_msg[prev_original_idx].processed_plain_text or "") - if not up_content: - # 上一句为空,跳过该表达 + # 当前行的原始内容 + current_msg = random_msg[line_index] + context = filter_message_content(current_msg.processed_plain_text or "") + if not context: continue - filtered_with_up.append((situation, style, context, up_content)) - if not filtered_with_up: + filtered_expressions.append((situation, style, context)) + + if not filtered_expressions: return None - return filtered_with_up + return filtered_expressions def parse_expression_response(self, response: str) -> List[Tuple[str, str, str]]: """ - 解析LLM返回的表达风格总结,每一行提取"当"和"使用"之间的内容,存储为(situation, style)元组 + 解析 LLM 返回的表达风格总结 JSON,提取 (situation, style, source_id) 元组列表。 + + 期望的 JSON 结构: + [ + {"situation": "AAAAA", "style": "BBBBB", "source_id": "3"}, + ... + ] """ + if not response: + return [] + + raw = response.strip() + + # 尝试提取 ```json 代码块 + json_block_pattern = r"```json\s*(.*?)\s*```" + match = re.search(json_block_pattern, raw, re.DOTALL) + if match: + raw = match.group(1).strip() + else: + # 去掉可能存在的通用 ``` 包裹 + raw = re.sub(r"^```\s*", "", raw, flags=re.MULTILINE) + raw = re.sub(r"```\s*$", "", raw, flags=re.MULTILINE) + raw = raw.strip() + + parsed = None expressions: List[Tuple[str, str, str]] = [] - for line in response.splitlines(): - line = line.strip() - if not line: + + try: + # 优先尝试直接解析 + if raw.startswith("[") and raw.endswith("]"): + parsed = json.loads(raw) + else: + repaired = repair_json(raw) + if isinstance(repaired, str): + parsed = json.loads(repaired) + else: + parsed = repaired + except Exception: + logger.error(f"解析表达风格 JSON 失败,原始响应:{response}") + return [] + + if isinstance(parsed, dict): + parsed_list = [parsed] + elif isinstance(parsed, list): + parsed_list = parsed + else: + logger.error(f"表达风格解析结果类型异常: {type(parsed)}, 内容: {parsed}") + return [] + + for item in parsed_list: + if not isinstance(item, dict): continue - # 查找"当"和下一个引号 - idx_when = line.find('当"') - if idx_when == -1: + situation = str(item.get("situation", "")).strip() + style = str(item.get("style", "")).strip() + source_id = str(item.get("source_id", "")).strip() + if not situation or not style or not source_id: + # 三个字段必须同时存在 continue - idx_quote1 = idx_when + 1 - idx_quote2 = line.find('"', idx_quote1 + 1) - if idx_quote2 == -1: - continue - situation = line[idx_quote1 + 1 : idx_quote2] - # 查找"使用" - idx_use = line.find('使用"', idx_quote2) - if idx_use == -1: - continue - idx_quote3 = idx_use + 2 - idx_quote4 = line.find('"', idx_quote3 + 1) - if idx_quote4 == -1: - continue - style = line[idx_quote3 + 1 : idx_quote4] - expressions.append((situation, style)) + expressions.append((situation, style, source_id)) + return expressions - def _filter_self_reference_styles(self, expressions: List[Tuple[str, str]]) -> List[Tuple[str, str]]: + def _filter_self_reference_styles(self, expressions: List[Tuple[str, str, str]]) -> List[Tuple[str, str, str]]: """ 过滤掉style与机器人名称/昵称重复的表达 """ @@ -525,12 +361,12 @@ class ExpressionLearner: banned_casefold = {name.casefold() for name in banned_names if name} - filtered: List[Tuple[str, str]] = [] + filtered: List[Tuple[str, str, str]] = [] removed_count = 0 - for situation, style in expressions: + for situation, style, source_id in expressions: normalized_style = (style or "").strip() if normalized_style and normalized_style.casefold() not in banned_casefold: - filtered.append((situation, style)) + filtered.append((situation, style, source_id)) else: removed_count += 1 @@ -544,7 +380,6 @@ class ExpressionLearner: situation: str, style: str, context: str, - up_content: str, current_time: float, ) -> None: expr_obj = Expression.select().where((Expression.chat_id == self.chat_id) & (Expression.style == style)).first() @@ -554,7 +389,6 @@ class ExpressionLearner: expr_obj=expr_obj, situation=situation, context=context, - up_content=up_content, current_time=current_time, ) return @@ -563,7 +397,6 @@ class ExpressionLearner: situation=situation, style=style, context=context, - up_content=up_content, current_time=current_time, ) @@ -572,7 +405,6 @@ class ExpressionLearner: situation: str, style: str, context: str, - up_content: str, current_time: float, ) -> None: content_list = [situation] @@ -587,7 +419,6 @@ class ExpressionLearner: chat_id=self.chat_id, create_date=current_time, context=context, - up_content=up_content, ) async def _update_existing_expression( @@ -595,7 +426,6 @@ class ExpressionLearner: expr_obj: Expression, situation: str, context: str, - up_content: str, current_time: float, ) -> None: content_list = self._parse_content_list(expr_obj.content_list) @@ -605,7 +435,6 @@ class ExpressionLearner: expr_obj.count = (expr_obj.count or 0) + 1 expr_obj.last_active_time = current_time expr_obj.context = context - expr_obj.up_content = up_content new_situation = await self._compose_situation_text( content_list=content_list, @@ -651,27 +480,6 @@ class ExpressionLearner: logger.error(f"概括表达情境失败: {e}") return None - def _build_bare_lines(self, messages: List) -> List[Tuple[int, str]]: - """ - 为每条消息构建精简文本列表,保留到原消息索引的映射 - - Args: - messages: 消息列表 - - Returns: - List[Tuple[int, str]]: (original_index, bare_content) 元组列表 - """ - bare_lines: List[Tuple[int, str]] = [] - - for idx, msg in enumerate(messages): - content = msg.processed_plain_text or "" - content = filter_message_content(content) - # 即使content为空也要记录,防止错位 - bare_lines.append((idx, content)) - - return bare_lines - - init_prompt() diff --git a/src/hippo_memorizer/chat_history_summarizer.py b/src/hippo_memorizer/chat_history_summarizer.py index 70847de0..456a0f2e 100644 --- a/src/hippo_memorizer/chat_history_summarizer.py +++ b/src/hippo_memorizer/chat_history_summarizer.py @@ -429,15 +429,36 @@ class ChatHistorySummarizer: # 2. 构造编号后的消息字符串和参与者信息 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. 调用 LLM 识别话题,并得到 topic -> indices(失败时最多重试 3 次) existing_topics = list(self.topic_cache.keys()) - success, topic_to_indices = await self._analyze_topics_with_llm( - numbered_lines=numbered_lines, - existing_topics=existing_topics, - ) + max_retries = 3 + attempt = 0 + success = False + topic_to_indices: Dict[str, List[int]] = {} + + while attempt < max_retries: + attempt += 1 + success, topic_to_indices = await self._analyze_topics_with_llm( + numbered_lines=numbered_lines, + existing_topics=existing_topics, + ) + + if success and topic_to_indices: + if attempt > 1: + logger.info( + f"{self.log_prefix} 话题识别在第 {attempt} 次重试后成功 | 话题数: {len(topic_to_indices)}" + ) + break + + logger.warning( + f"{self.log_prefix} 话题识别失败或无有效话题,第 {attempt} 次尝试失败" + + ("" if attempt >= max_retries else ",准备重试") + ) if not success or not topic_to_indices: - logger.warning(f"{self.log_prefix} 话题识别失败或无有效话题,本次检查忽略") + logger.error( + f"{self.log_prefix} 话题识别连续 {max_retries} 次失败或始终无有效话题,本次检查放弃" + ) # 即使识别失败,也认为是一次“检查”,但不更新 no_update_checks(保持原状) return diff --git a/src/chat/utils/memory_forget_task.py b/src/hippo_memorizer/memory_forget_task.py similarity index 98% rename from src/chat/utils/memory_forget_task.py rename to src/hippo_memorizer/memory_forget_task.py index cd9144a1..ce2a9b2a 100644 --- a/src/chat/utils/memory_forget_task.py +++ b/src/hippo_memorizer/memory_forget_task.py @@ -28,10 +28,10 @@ class MemoryForgetTask(AsyncTask): # logger.info("[记忆遗忘] 开始遗忘检查...") # 执行4个阶段的遗忘检查 - await self._forget_stage_1(current_time) - await self._forget_stage_2(current_time) - await self._forget_stage_3(current_time) - await self._forget_stage_4(current_time) + # await self._forget_stage_1(current_time) + # await self._forget_stage_2(current_time) + # await self._forget_stage_3(current_time) + # await self._forget_stage_4(current_time) # logger.info("[记忆遗忘] 遗忘检查完成") except Exception as e: diff --git a/src/llm_models/utils_model.py b/src/llm_models/utils_model.py index 44ff2de3..7fb4cfd0 100644 --- a/src/llm_models/utils_model.py +++ b/src/llm_models/utils_model.py @@ -315,12 +315,30 @@ class LLMRequest: while retry_remain > 0: try: if request_type == RequestType.RESPONSE: + # 温度优先级:参数传入 > 模型级别配置 > extra_params > 任务配置 + effective_temperature = temperature + if effective_temperature is None: + effective_temperature = model_info.temperature + if effective_temperature is None: + 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: + effective_max_tokens = model_info.max_tokens + if effective_max_tokens is None: + 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), tool_options=tool_options, - max_tokens=self.model_for_task.max_tokens if max_tokens is None else max_tokens, - temperature=temperature if temperature is not None else (model_info.extra_params or {}).get("temperature", self.model_for_task.temperature), + max_tokens=effective_max_tokens, + temperature=effective_temperature, response_format=response_format, stream_response_handler=stream_response_handler, async_response_parser=async_response_parser, diff --git a/src/main.py b/src/main.py index 3bcc9695..d2ca213b 100644 --- a/src/main.py +++ b/src/main.py @@ -16,6 +16,7 @@ from src.common.server import get_global_server, Server from src.mood.mood_manager import mood_manager from src.chat.knowledge import lpmm_start_up from rich.traceback import install + # from src.api.main import start_api_server # 导入新的插件管理器 @@ -23,6 +24,7 @@ from src.plugin_system.core.plugin_manager import plugin_manager # 导入消息API和traceback模块 from src.common.message import get_global_api +from src.dream.dream_agent import start_dream_scheduler # 插件系统现在使用统一的插件加载器 @@ -106,7 +108,7 @@ class MainSystem: await async_task_manager.add_task(TelemetryHeartBeatTask()) # 添加记忆遗忘任务 - from src.chat.utils.memory_forget_task import MemoryForgetTask + from src.hippo_memorizer.memory_forget_task import MemoryForgetTask await async_task_manager.add_task(MemoryForgetTask()) @@ -159,6 +161,7 @@ class MainSystem: try: tasks = [ get_emoji_manager().start_periodic_check_register(), + start_dream_scheduler(), self.app.run(), self.server.run(), ] diff --git a/src/memory_system/retrieval_tools/query_chat_history.py b/src/memory_system/retrieval_tools/query_chat_history.py index 097632c4..0d2d2cc7 100644 --- a/src/memory_system/retrieval_tools/query_chat_history.py +++ b/src/memory_system/retrieval_tools/query_chat_history.py @@ -5,11 +5,13 @@ import json from typing import Optional +from datetime import datetime + from src.common.logger import get_logger from src.common.database.database_model import ChatHistory from src.chat.utils.utils import parse_keywords_string +from src.config.config import global_config from .tool_registry import register_memory_retrieval_tool -from datetime import datetime logger = get_logger("memory_retrieval_tools") @@ -33,7 +35,18 @@ async def search_chat_history( return "未指定查询参数(需要提供keyword或participant之一)" # 构建查询条件 - query = ChatHistory.select().where(ChatHistory.chat_id == chat_id) + # 根据配置决定是否限制在当前 chat_id 内查询 + use_global_search = global_config.memory.global_memory + + if use_global_search: + # 全局查询所有聊天记录 + query = ChatHistory.select() + logger.debug( + f"search_chat_history 启用全局查询模式,忽略 chat_id 过滤,keyword={keyword}, participant={participant}" + ) + else: + # 仅在当前聊天流内查询 + query = ChatHistory.select().where(ChatHistory.chat_id == chat_id) # 执行查询 records = list(query.order_by(ChatHistory.start_time.desc()).limit(50)) @@ -139,9 +152,45 @@ async def search_chat_history( else: return "未找到相关聊天记录" - # 构建结果文本,返回id、theme和keywords + # 如果匹配结果超过20条,不返回具体记录,只返回提示和所有相关关键词 + if len(filtered_records) > 20: + # 统计所有记录上的关键词并去重 + all_keywords_set = set() + for record in filtered_records: + if record.keywords: + try: + keywords_data = ( + json.loads(record.keywords) + if isinstance(record.keywords, str) + else record.keywords + ) + if isinstance(keywords_data, list): + for k in keywords_data: + k_str = str(k).strip() + if k_str: + all_keywords_set.add(k_str) + except (json.JSONDecodeError, TypeError, ValueError): + continue + + # xxx 使用用户原始查询词,优先 keyword,其次 participant,最后退化成“当前条件” + search_label = keyword or participant or "当前条件" + + if all_keywords_set: + keywords_str = "、".join(sorted(all_keywords_set)) + return ( + f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" + f"有关\"{search_label}\"的关键词:\n" + f"{keywords_str}" + ) + else: + return ( + f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" + f"有关\"{search_label}\"的关键词信息为空" + ) + + # 构建结果文本,返回id、theme和keywords(最多20条) results = [] - for record in filtered_records[:20]: # 最多返回20条记录 + for record in filtered_records[:20]: result_parts = [] # 添加记忆ID @@ -173,9 +222,6 @@ async def search_chat_history( return "未找到相关聊天记录" response_text = "\n\n---\n\n".join(results) - if len(filtered_records) > 20: - omitted_count = len(filtered_records) - 20 - response_text += f"\n\n(还有{omitted_count}条记录已省略,可使用记忆ID查询详细信息)" return response_text except Exception as e: diff --git a/src/plugin_system/apis/message_api.py b/src/plugin_system/apis/message_api.py index 6a4805b2..94ee9cbc 100644 --- a/src/plugin_system/apis/message_api.py +++ b/src/plugin_system/apis/message_api.py @@ -72,7 +72,7 @@ def get_messages_by_time_in_chat( limit_mode: str = "latest", filter_mai: bool = False, filter_command: bool = False, - filter_no_read_command: bool = False, + filter_intercept_message_level: Optional[int] = None, ) -> List[DatabaseMessages]: """ 获取指定聊天中指定时间范围内的消息 @@ -111,7 +111,7 @@ def get_messages_by_time_in_chat( limit_mode=limit_mode, filter_bot=filter_mai, filter_command=filter_command, - filter_no_read_command=filter_no_read_command, + filter_intercept_message_level=filter_intercept_message_level, ) @@ -123,7 +123,7 @@ def get_messages_by_time_in_chat_inclusive( limit_mode: str = "latest", filter_mai: bool = False, filter_command: bool = False, - filter_no_read_command: bool = False, + filter_intercept_message_level: Optional[int] = None, ) -> List[DatabaseMessages]: """ 获取指定聊天中指定时间范围内的消息(包含边界) @@ -158,7 +158,7 @@ def get_messages_by_time_in_chat_inclusive( limit_mode=limit_mode, filter_bot=filter_mai, filter_command=filter_command, - filter_no_read_command=filter_no_read_command, + filter_intercept_message_level=filter_intercept_message_level, ) if filter_mai: return filter_mai_messages(messages) @@ -284,7 +284,7 @@ def get_messages_before_time_in_chat( timestamp: float, limit: int = 0, filter_mai: bool = False, - filter_no_read_command: bool = False, + filter_intercept_message_level: Optional[int] = None, ) -> List[DatabaseMessages]: """ 获取指定聊天中指定时间戳之前的消息 @@ -313,7 +313,7 @@ def get_messages_before_time_in_chat( chat_id=chat_id, timestamp=timestamp, limit=limit, - filter_no_read_command=filter_no_read_command, + filter_intercept_message_level=filter_intercept_message_level, ) if filter_mai: return filter_mai_messages(messages) diff --git a/src/plugin_system/base/base_command.py b/src/plugin_system/base/base_command.py index 4b098869..0cfdb5d0 100644 --- a/src/plugin_system/base/base_command.py +++ b/src/plugin_system/base/base_command.py @@ -55,11 +55,11 @@ class BaseCommand(ABC): self.matched_groups = groups @abstractmethod - async def execute(self) -> Tuple[bool, Optional[str], bool]: + async def execute(self) -> Tuple[bool, Optional[str], int]: """执行Command的抽象方法,子类必须实现 Returns: - Tuple[bool, Optional[str], bool]: (是否执行成功, 可选的回复消息, 是否拦截消息 不进行 后续处理) + Tuple[bool, Optional[str], int]: (是否执行成功, 可选的回复消息, 拦截消息力度,0代表不拦截,1代表仅不触发回复,replyer可见,2代表不触发回复,replyer不可见) """ pass diff --git a/src/webui/config_routes.py b/src/webui/config_routes.py index 5e54c8f7..63803d5e 100644 --- a/src/webui/config_routes.py +++ b/src/webui/config_routes.py @@ -8,7 +8,7 @@ from fastapi import APIRouter, HTTPException, Body from typing import Any, Annotated from src.common.logger import get_logger -from src.common.toml_utils import save_toml_with_format +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 ( BotConfig, @@ -51,40 +51,6 @@ PathBody = Annotated[dict[str, str], Body()] router = APIRouter(prefix="/config", tags=["config"]) -# ===== 辅助函数 ===== - - -def _update_dict_preserve_comments(target: Any, source: Any) -> None: - """ - 递归合并字典,保留 target 中的注释和格式 - 将 source 的值更新到 target 中(仅更新已存在的键) - - Args: - target: 目标字典(tomlkit 对象,包含注释) - source: 源字典(普通 dict 或 list) - """ - # 如果 source 是列表,直接替换(数组表没有注释保留的意义) - if isinstance(source, list): - return # 调用者需要直接赋值 - - # 如果都是字典,递归合并 - if isinstance(source, dict) and isinstance(target, dict): - for key, value in source.items(): - if key == "version": - continue # 跳过版本号 - if key in target: - target_value = target[key] - # 递归处理嵌套字典 - if isinstance(value, dict) and isinstance(target_value, dict): - _update_dict_preserve_comments(target_value, value) - else: - # 使用 tomlkit.item 保持类型 - try: - target[key] = tomlkit.item(value) - except (TypeError, ValueError): - target[key] = value - - # ===== 架构获取接口 ===== @@ -238,7 +204,7 @@ async def update_bot_config(config_data: ConfigBody): except Exception as e: raise HTTPException(status_code=400, detail=f"配置数据验证失败: {str(e)}") from e - # 保存配置文件(格式化数组为多行) + # 保存配置文件(自动保留注释和格式) config_path = os.path.join(CONFIG_DIR, "bot_config.toml") save_toml_with_format(config_data, config_path) @@ -261,7 +227,7 @@ async def update_model_config(config_data: ConfigBody): except Exception as e: raise HTTPException(status_code=400, detail=f"配置数据验证失败: {str(e)}") from e - # 保存配置文件(格式化数组为多行) + # 保存配置文件(自动保留注释和格式) config_path = os.path.join(CONFIG_DIR, "model_config.toml") save_toml_with_format(config_data, config_path) @@ -300,7 +266,7 @@ async def update_bot_config_section(section_name: str, section_data: SectionBody config_data[section_name] = section_data elif isinstance(section_data, dict) and isinstance(config_data[section_name], dict): # 字典递归合并 - _update_dict_preserve_comments(config_data[section_name], section_data) + _update_toml_doc(config_data[section_name], section_data) else: # 其他类型直接替换 config_data[section_name] = section_data @@ -398,7 +364,7 @@ async def update_model_config_section(section_name: str, section_data: SectionBo config_data[section_name] = section_data elif isinstance(section_data, dict) and isinstance(config_data[section_name], dict): # 字典递归合并 - _update_dict_preserve_comments(config_data[section_name], section_data) + _update_toml_doc(config_data[section_name], section_data) else: # 其他类型直接替换 config_data[section_name] = section_data diff --git a/src/webui/expression_routes.py b/src/webui/expression_routes.py index bef93b30..1fa0ce7d 100644 --- a/src/webui/expression_routes.py +++ b/src/webui/expression_routes.py @@ -1,7 +1,7 @@ """表达方式管理 API 路由""" from fastapi import APIRouter, HTTPException, Header, Query, Cookie -from pydantic import BaseModel +from pydantic import BaseModel, NonNegativeFloat from typing import Optional, List, Dict from src.common.logger import get_logger from src.common.database.database_model import Expression, ChatStreams @@ -21,7 +21,6 @@ class ExpressionResponse(BaseModel): situation: str style: str context: Optional[str] - up_content: Optional[str] last_active_time: float chat_id: str create_date: Optional[float] @@ -49,8 +48,7 @@ class ExpressionCreateRequest(BaseModel): situation: str style: str - context: Optional[str] = None - up_content: Optional[str] = None + context: Optional[str] = NonNegativeFloat chat_id: str @@ -60,7 +58,6 @@ class ExpressionUpdateRequest(BaseModel): situation: Optional[str] = None style: Optional[str] = None context: Optional[str] = None - up_content: Optional[str] = None chat_id: Optional[str] = None @@ -102,7 +99,6 @@ def expression_to_response(expression: Expression) -> ExpressionResponse: situation=expression.situation, style=expression.style, context=expression.context, - up_content=expression.up_content, last_active_time=expression.last_active_time, chat_id=expression.chat_id, create_date=expression.create_date, @@ -310,7 +306,6 @@ async def create_expression(request: ExpressionCreateRequest, maibot_session: Op situation=request.situation, style=request.style, context=request.context, - up_content=request.up_content, chat_id=request.chat_id, last_active_time=current_time, create_date=current_time, diff --git a/src/webui/plugin_routes.py b/src/webui/plugin_routes.py index 1f2d85da..9eedc9d7 100644 --- a/src/webui/plugin_routes.py +++ b/src/webui/plugin_routes.py @@ -1420,18 +1420,8 @@ async def update_plugin_config( shutil.copy(config_path, backup_path) logger.info(f"已备份配置文件: {backup_path}") - # 写入新配置(使用 tomlkit 保留注释) - import tomlkit - - # 先读取原配置以保留注释和格式 - existing_doc = tomlkit.document() - if config_path.exists(): - with open(config_path, "r", encoding="utf-8") as f: - existing_doc = tomlkit.load(f) - # 更新值 - for key, value in request.config.items(): - existing_doc[key] = value - save_toml_with_format(existing_doc, str(config_path)) + # 写入新配置(自动保留注释和格式) + save_toml_with_format(request.config, str(config_path)) logger.info(f"已更新插件配置: {plugin_id}") diff --git a/src/webui/routes.py b/src/webui/routes.py index 2c0fc9f7..96942f1d 100644 --- a/src/webui/routes.py +++ b/src/webui/routes.py @@ -223,9 +223,9 @@ async def update_token( # 更新 token success, message = token_manager.update_token(request.new_token) - # 如果更新成功,更新 Cookie + # 如果更新成功,清除 Cookie,要求用户重新登录 if success: - set_auth_cookie(response, request.new_token) + clear_auth_cookie(response) return TokenUpdateResponse(success=success, message=message) except HTTPException: @@ -272,8 +272,8 @@ async def regenerate_token( # 重新生成 token new_token = token_manager.regenerate_token() - # 更新 Cookie - set_auth_cookie(response, new_token) + # 清除 Cookie,要求用户重新登录 + clear_auth_cookie(response) return TokenRegenerateResponse(success=True, token=new_token, message="Token 已重新生成") except HTTPException: diff --git a/src/webui/token_manager.py b/src/webui/token_manager.py index 69abf1d8..17e3f068 100644 --- a/src/webui/token_manager.py +++ b/src/webui/token_manager.py @@ -160,13 +160,29 @@ class TokenManager: def regenerate_token(self) -> str: """ - 重新生成 token + 重新生成 token(保留 first_setup_completed 状态) Returns: str: 新生成的 token """ logger.info("正在重新生成 WebUI Token...") - return self._create_new_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/template/bot_config_template.toml b/template/bot_config_template.toml index 9daf8739..a978c93a 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "6.23.5" +version = "7.0.2" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- # 如果你想要修改配置文件,请递增version的值 @@ -69,6 +69,7 @@ learning_list = [ # 表达学习配置列表,支持按聊天流配置 # 第三位: 是否学习表达 ("enable"/"disable") # 第四位: 学习强度(浮点数),影响学习频率,最短学习时间间隔 = 300/学习强度(秒) # 学习强度越高,学习越频繁;学习强度越低,学习越少 + # 如果学习强度设置为0会自动转换为0.0001以避免除以零错误 ] expression_groups = [ @@ -86,7 +87,7 @@ allow_reflect = [] # 允许进行表达反思的聊天流ID列表,格式:["q [chat] # 麦麦的聊天设置 -talk_value = 1 # 聊天频率,越小越沉默,范围0-1 +talk_value = 1 # 聊天频率,越小越沉默,范围0-1,如果设置为0会自动转换为0.0001以避免除以零错误 mentioned_bot_reply = true # 是否启用提及必回复 max_context_size = 30 # 上下文长度 planner_smooth = 2 # 规划器平滑,增大数值会减小planner负荷,略微降低反应速度,推荐1-5,0为关闭,必须大于等于0 @@ -97,7 +98,7 @@ enable_talk_value_rules = true # 是否启用动态发言频率规则 # 推荐格式(对象数组):{ target="platform:id:type" 或 "", time="HH:MM-HH:MM", value=0.5 } # 说明: # - target 为空字符串表示全局;type 为 group/private,例如:"qq:1919810:group" 或 "qq:114514:private"; -# - 支持跨夜区间,例如 "23:00-02:00";数值范围建议 0-1。 +# - 支持跨夜区间,例如 "23:00-02:00";数值范围建议 0-1,如果 value 设置为0会自动转换为0.0001以避免除以零错误。 talk_value_rules = [ { target = "", time = "00:00-08:59", value = 0.8 }, { target = "", time = "09:00-22:59", value = 1.0 }, @@ -110,6 +111,24 @@ include_planner_reasoning = false # 是否将planner推理加入replyer,默认 [memory] max_agent_iterations = 3 # 记忆思考深度(最低为1(不深入思考)) enable_jargon_detection = true # 记忆检索过程中是否启用黑话识别 +global_memory = false # 是否允许记忆检索进行全局查询 + +[dream] +interval_minutes = 45 # 做梦时间间隔(分钟),默认30分钟 +max_iterations = 20 # 做梦最大轮次,默认20轮 +first_delay_seconds = 1200 # 程序启动后首次做梦前的延迟时间(秒),默认60秒 + +# 做梦时间段配置,格式:["HH:MM-HH:MM", ...] +# 如果列表为空,则表示全天允许做梦。 +# 如果配置了时间段,则只有在这些时间段内才会实际执行做梦流程。 +# 时间段外,调度器仍会按间隔检查,但不会进入做梦流程。 +# 支持跨夜区间,例如 "23:00-02:00" 表示从23:00到次日02:00。 +# 示例: +dream_time_ranges = [ + # "09:00-22:00", # 白天允许做梦 + "23:00-10:00", # 跨夜时间段(23:00到次日10:00) +] +# dream_time_ranges = [] [jargon] all_global = true # 是否开启全局黑话模式,注意,此功能关闭后,已经记录的全局黑话不会改变,需要手动删除 diff --git a/template/model_config_template.toml b/template/model_config_template.toml index 1e072d13..225b94f1 100644 --- a/template/model_config_template.toml +++ b/template/model_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "1.8.2" +version = "1.9.0" # 配置文件版本号迭代规则同bot_config.toml @@ -54,9 +54,11 @@ name = "siliconflow-deepseek-v3.2" api_provider = "SiliconFlow" price_in = 2.0 price_out = 3.0 +# temperature = 0.5 # 可选:为该模型单独指定温度,会覆盖任务配置中的温度 +# max_tokens = 4096 # 可选:为该模型单独指定最大token数,会覆盖任务配置中的max_tokens [models.extra_params] # 可选的额外参数配置 enable_thinking = false # 不启用思考 -# temperature = 0.5 # 可选:为该模型单独指定温度,会覆盖任务配置中的温度 + [[models]] model_identifier = "deepseek-ai/DeepSeek-V3.2-Exp" @@ -64,9 +66,11 @@ name = "siliconflow-deepseek-v3.2-think" api_provider = "SiliconFlow" price_in = 2.0 price_out = 3.0 +# temperature = 0.7 # 可选:为该模型单独指定温度,会覆盖任务配置中的温度 +# max_tokens = 4096 # 可选:为该模型单独指定最大token数,会覆盖任务配置中的max_tokens [models.extra_params] # 可选的额外参数配置 enable_thinking = true # 启用思考 -# temperature = 0.7 # 可选:为该模型单独指定温度,会覆盖任务配置中的温度 + [[models]] model_identifier = "Qwen/Qwen3-Next-80B-A3B-Instruct" diff --git a/webui/dist/assets/index-DM1UfLap.css b/webui/dist/assets/index-DM1UfLap.css new file mode 100644 index 00000000..997524d6 --- /dev/null +++ b/webui/dist/assets/index-DM1UfLap.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}.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-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-\[--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-\[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-\[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\:col-span-2{grid-column:span 2 / span 2}.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-10{grid-template-columns:repeat(10,minmax(0,1fr))}.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\: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}.\[\&\: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-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.25"}.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-QJDQd8Xo.css b/webui/dist/assets/index-QJDQd8Xo.css deleted file mode 100644 index 06b5dafa..00000000 --- a/webui/dist/assets/index-QJDQd8Xo.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-\[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-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-\[--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-\[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-\[300px\]{min-height:300px}.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-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{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-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-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-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-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-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-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-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\:col-span-2{grid-column:span 2 / span 2}.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-10{grid-template-columns:repeat(10,minmax(0,1fr))}.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\: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}.\[\&\: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-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.25"}.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-DJb_iiTR.js b/webui/dist/assets/index-siV9e-l5.js similarity index 51% rename from webui/dist/assets/index-DJb_iiTR.js rename to webui/dist/assets/index-siV9e-l5.js index 886bc66f..40b8c501 100644 --- a/webui/dist/assets/index-DJb_iiTR.js +++ b/webui/dist/assets/index-siV9e-l5.js @@ -1,42 +1,44 @@ -import{r as u,j as e,L as Yc,e as ga,b as lN,f as nN,g as iN,h as rN,k as ft,l as cN,m as oN,O as vp,n as dN}from"./router-CWhjJi2n.js";import{a as uN,b as mN,g as hN}from"./react-vendor-Dtc2IqVY.js";import{I as xN,c as fN,J as ci,K as Bc,L as vu,M as pN,N as tr,O as ar,P as gN,n as Nu}from"./utils-CCeOswSm.js";import{L as Np,T as bp,C as yp,R as jN,a as wp,V as vN,b as NN,S as _p,c as bN,d as Sp,I as yN,e as Cp,f as wN,g as kp,h as _N,i as SN,j as CN,O as Tp,P as kN,k as Ep,l as zp,D as Ap,A as Mp,m as Dp,n as TN,o as EN,p as Op,q as zN,r as Rp,s as AN,t as MN,u as DN,v as ON,w as RN,x as Lp,y as Up,F as Bp}from"./radix-extra-BM7iD6Dt.js";import{aj as LN,ak as UN,al as BN,am as HN,an as Hc,ao as qc,ap as lr,aq as qN,ar as bu,as as Gc,at as GN,au as VN,av as FN}from"./charts-Dhri-zxi.js";import{S as $N,G as Hp,O as qp,o as QN,C as Gp,p as YN,T as Vp,D as Fp,R as XN,q as KN,H as $p,I as JN,J as Qp,K as Yp,L as ZN,M as Xp,V as IN,N as Kp,Q as Jp,U as PN,X as WN,Y as Zp,Z as eb,_ as sb,$ as Ip,a0 as tb,a1 as ab,a2 as Pp,a3 as lb,a4 as nb,a5 as ib,a6 as Wp,a7 as eg,a8 as sg,a9 as tg,aa as ag,ab as lg,ac as rb}from"./radix-core-C3XKqQJw.js";import{R as Ct,P as br,C as fa,a as Oa,Z as cn,b as Zc,F as Da,c as cb,S as oi,A as ob,D as db,d as Ic,e as li,M as un,T as ub,X as dl,f as mb,g as hb,I as Ra,h as ya,i as sa,j as Pc,E as xr,k as Dt,l as ng,H as xb,m as ls,n as rl,U as fr,o as ig,p as rg,L as $f,K as cg,q as og,r as fb,s as Xc,t as kt,u as pb,B as cr,v as Wc,w as Gu,x as gb,y as jb,z as zt,G as ao,J as ii,N as Bl,O as pr,Q as yr,V as vb,W as Nb,Y as xt,_ as Vu,$ as on,a0 as di,a1 as Hl,a2 as ul,a3 as ui,a4 as Fu,a5 as bb,a6 as yb,a7 as wb,a8 as dn,a9 as _b,aa as dg,ab as Mu,ac as mn,ad as Sb,ae as ri,af as Cb,ag as Du,ah as Ou,ai as ug,aj as Qf,ak as kb,al as Tb,am as Eb,an as Ul,ao as yu,ap as Yf,aq as zb,ar as wu,as as Ab,at as Mb,au as Db,av as Ob,aw as mg,ax as hg,ay as xg,az as Rb,aA as Xf,aB as Lb,aC as Ub,aD as Bb,aE as Hb}from"./icons-DUfC2NKX.js";import{S as qb,p as Gb,j as Vb,a as Fb,E as Kf,R as $b,o as Qb}from"./codemirror-BHeANvwm.js";import{_ as $t,c as Yb,g as fg,D as Xb}from"./misc-DyBU7ISD.js";import{u as Kb,a as Jf,D as Jb,c as Zb,S as Ib,h as Pb,b as Wb,s as ey,K as sy,P as ty,d as ay,C as ly}from"./dnd-Dyi3CnuX.js";import{D as ny,U as iy}from"./uppy-BHC3OXBx.js";import{M as ry,r as cy,a as oy,b as dy}from"./markdown-A1ShuLvG.js";import{r as uy,H as eo,P as so,u as my,a as hy,R as xy,B as fy,b as py,C as gy,M as jy,c as vy}from"./reactflow-B3n3_Vkw.js";(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const h of document.querySelectorAll('link[rel="modulepreload"]'))d(h);new MutationObserver(h=>{for(const x of h)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 c(h){const x={};return h.integrity&&(x.integrity=h.integrity),h.referrerPolicy&&(x.referrerPolicy=h.referrerPolicy),h.crossOrigin==="use-credentials"?x.credentials="include":h.crossOrigin==="anonymous"?x.credentials="omit":x.credentials="same-origin",x}function d(h){if(h.ep)return;h.ep=!0;const x=c(h);fetch(h.href,x)}})();var _u={exports:{}},nr={},Su={exports:{}},Cu={};var Zf;function Ny(){return Zf||(Zf=1,(function(n){function i(z,X){var k=z.length;z.push(X);e:for(;0>>1,_=z[se];if(0>>1;seh(ae,k))fe<_&&0>h(Ne,ae)?(z[se]=Ne,z[fe]=k,se=fe):(z[se]=ae,z[ie]=k,se=ie);else if(fe<_&&0>h(Ne,k))z[se]=Ne,z[fe]=k,se=fe;else break e}}return X}function h(z,X){var k=z.sortIndex-X.sortIndex;return k!==0?k:z.id-X.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,j=f.now();n.unstable_now=function(){return f.now()-j}}var p=[],w=[],v=1,y=null,S=3,C=!1,M=!1,F=!1,U=!1,O=typeof setTimeout=="function"?setTimeout:null,K=typeof clearTimeout=="function"?clearTimeout:null,H=typeof setImmediate<"u"?setImmediate:null;function A(z){for(var X=c(w);X!==null;){if(X.callback===null)d(w);else if(X.startTime<=z)d(w),X.sortIndex=X.expirationTime,i(p,X);else break;X=c(w)}}function V(z){if(F=!1,A(z),!M)if(c(p)!==null)M=!0,Q||(Q=!0,Se());else{var X=c(w);X!==null&&be(V,X.startTime-z)}}var Q=!1,T=-1,D=5,ne=-1;function xe(){return U?!0:!(n.unstable_now()-nez&&xe());){var se=y.callback;if(typeof se=="function"){y.callback=null,S=y.priorityLevel;var _=se(y.expirationTime<=z);if(z=n.unstable_now(),typeof _=="function"){y.callback=_,A(z),X=!0;break s}y===c(p)&&d(p),A(z)}else d(p);y=c(p)}if(y!==null)X=!0;else{var ue=c(w);ue!==null&&be(V,ue.startTime-z),X=!1}}break e}finally{y=null,S=k,C=!1}X=void 0}}finally{X?Se():Q=!1}}}var Se;if(typeof H=="function")Se=function(){H(_e)};else if(typeof MessageChannel<"u"){var ge=new MessageChannel,ye=ge.port2;ge.port1.onmessage=_e,Se=function(){ye.postMessage(null)}}else Se=function(){O(_e,0)};function be(z,X){T=O(function(){z(n.unstable_now())},X)}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(z){z.callback=null},n.unstable_forceFrameRate=function(z){0>z||125se?(z.sortIndex=k,i(w,z),c(p)===null&&z===c(w)&&(F?(K(T),T=-1):F=!0,be(V,k-se))):(z.sortIndex=_,i(p,z),M||C||(M=!0,Q||(Q=!0,Se()))),z},n.unstable_shouldYield=xe,n.unstable_wrapCallback=function(z){var X=S;return function(){var k=S;S=X;try{return z.apply(this,arguments)}finally{S=k}}}})(Cu)),Cu}var If;function by(){return If||(If=1,Su.exports=Ny()),Su.exports}var Pf;function yy(){if(Pf)return nr;Pf=1;var n=by(),i=uN(),c=mN();function d(s){var t="https://react.dev/errors/"+s;if(1_||(s.current=se[_],se[_]=null,_--)}function ae(s,t){_++,se[_]=s.current,s.current=t}var fe=ue(null),Ne=ue(null),me=ue(null),G=ue(null);function P(s,t){switch(ae(me,t),ae(Ne,s),ae(fe,null),t.nodeType){case 9:case 11:s=(s=t.documentElement)&&(s=s.namespaceURI)?hf(s):0;break;default:if(s=t.tagName,t=t.namespaceURI)t=hf(t),s=xf(t,s);else switch(s){case"svg":s=1;break;case"math":s=2;break;default:s=0}}ie(fe),ae(fe,s)}function B(){ie(fe),ie(Ne),ie(me)}function W(s){s.memoizedState!==null&&ae(G,s);var t=fe.current,a=xf(t,s.type);t!==a&&(ae(Ne,s),ae(fe,a))}function Ce(s){Ne.current===s&&(ie(fe),ie(Ne)),G.current===s&&(ie(G),Pi._currentValue=k)}var Me,re;function De(s){if(Me===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);Me=t&&t[1]||"",re=-1{for(const f of h)if(f.type==="childList")for(const x of f.addedNodes)x.tagName==="LINK"&&x.rel==="modulepreload"&&d(x)}).observe(document,{childList:!0,subtree:!0});function c(h){const f={};return h.integrity&&(f.integrity=h.integrity),h.referrerPolicy&&(f.referrerPolicy=h.referrerPolicy),h.crossOrigin==="use-credentials"?f.credentials="include":h.crossOrigin==="anonymous"?f.credentials="omit":f.credentials="same-origin",f}function d(h){if(h.ep)return;h.ep=!0;const f=c(h);fetch(h.href,f)}})();var _u={exports:{}},nr={},Su={exports:{}},Cu={};var Wf;function _y(){return Wf||(Wf=1,(function(n){function i(A,K){var E=A.length;A.push(K);e:for(;0>>1,_=A[se];if(0>>1;seh(le,E))pe<_&&0>h(Ne,le)?(A[se]=Ne,A[pe]=E,se=pe):(A[se]=le,A[re]=E,se=re);else if(pe<_&&0>h(Ne,E))A[se]=Ne,A[pe]=E,se=pe;else break e}}return K}function h(A,K){var E=A.sortIndex-K.sortIndex;return E!==0?E:A.id-K.id}if(n.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var f=performance;n.unstable_now=function(){return f.now()}}else{var x=Date,j=x.now();n.unstable_now=function(){return x.now()-j}}var p=[],w=[],v=1,y=null,S=3,k=!1,O=!1,Y=!1,L=!1,R=typeof setTimeout=="function"?setTimeout:null,H=typeof clearTimeout=="function"?clearTimeout:null,D=typeof setImmediate<"u"?setImmediate:null;function C(A){for(var K=c(w);K!==null;){if(K.callback===null)d(w);else if(K.startTime<=A)d(w),K.sortIndex=K.expirationTime,i(p,K);else break;K=c(w)}}function $(A){if(Y=!1,C(A),!O)if(c(p)!==null)O=!0,G||(G=!0,Se());else{var K=c(w);K!==null&&be($,K.startTime-A)}}var G=!1,T=-1,M=5,ne=-1;function fe(){return L?!0:!(n.unstable_now()-neA&&fe());){var se=y.callback;if(typeof se=="function"){y.callback=null,S=y.priorityLevel;var _=se(y.expirationTime<=A);if(A=n.unstable_now(),typeof _=="function"){y.callback=_,C(A),K=!0;break s}y===c(p)&&d(p),C(A)}else d(p);y=c(p)}if(y!==null)K=!0;else{var me=c(w);me!==null&&be($,me.startTime-A),K=!1}}break e}finally{y=null,S=E,k=!1}K=void 0}}finally{K?Se():G=!1}}}var Se;if(typeof D=="function")Se=function(){D(_e)};else if(typeof MessageChannel<"u"){var je=new MessageChannel,ye=je.port2;je.port1.onmessage=_e,Se=function(){ye.postMessage(null)}}else Se=function(){R(_e,0)};function be(A,K){T=R(function(){A(n.unstable_now())},K)}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(A){A.callback=null},n.unstable_forceFrameRate=function(A){0>A||125se?(A.sortIndex=E,i(w,A),c(p)===null&&A===c(w)&&(Y?(H(T),T=-1):Y=!0,be($,E-se))):(A.sortIndex=_,i(p,A),O||k||(O=!0,G||(G=!0,Se()))),A},n.unstable_shouldYield=fe,n.unstable_wrapCallback=function(A){var K=S;return function(){var E=S;S=K;try{return A.apply(this,arguments)}finally{S=E}}}})(Cu)),Cu}var ep;function Sy(){return ep||(ep=1,Su.exports=_y()),Su.exports}var sp;function Cy(){if(sp)return nr;sp=1;var n=Sy(),i=fN(),c=pN();function d(s){var t="https://react.dev/errors/"+s;if(1_||(s.current=se[_],se[_]=null,_--)}function le(s,t){_++,se[_]=s.current,s.current=t}var pe=me(null),Ne=me(null),he=me(null),Q=me(null);function P(s,t){switch(le(he,t),le(Ne,s),le(pe,null),t.nodeType){case 9:case 11:s=(s=t.documentElement)&&(s=s.namespaceURI)?pf(s):0;break;default:if(s=t.tagName,t=t.namespaceURI)t=pf(t),s=gf(t,s);else switch(s){case"svg":s=1;break;case"math":s=2;break;default:s=0}}re(pe),le(pe,s)}function q(){re(pe),re(Ne),re(he)}function W(s){s.memoizedState!==null&&le(Q,s);var t=pe.current,a=gf(t,s.type);t!==a&&(le(Ne,s),le(pe,a))}function Ce(s){Ne.current===s&&(re(pe),re(Ne)),Q.current===s&&(re(Q),Pi._currentValue=E)}var Me,ce;function De(s){if(Me===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);Me=t&&t[1]||"",ce=-1)":-1r||E[l]!==Z[r]){var ce=` -`+E[l].replace(" at new "," at ");return s.displayName&&ce.includes("")&&(ce=ce.replace("",s.displayName)),ce}while(1<=l&&0<=r);break}}}finally{Vs=!1,Error.prepareStackTrace=a}return(a=s?s.displayName||s.name:"")?De(a):""}function de(s,t){switch(s.tag){case 26:case 27:case 5:return De(s.type);case 16:return De("Lazy");case 13:return s.child!==t&&t!==null?De("Suspense Fallback"):De("Suspense");case 19:return De("SuspenseList");case 0:case 15:return Qs(s.type,!1);case 11:return Qs(s.type.render,!1);case 1:return Qs(s.type,!0);case 31:return De("Activity");default:return""}}function Ee(s){try{var t="",a=null;do t+=de(s,a),a=s,s=s.return;while(s);return t}catch(l){return` +`);for(r=l=0;lr||z[l]!==Z[r]){var oe=` +`+z[l].replace(" at new "," at ");return s.displayName&&oe.includes("")&&(oe=oe.replace("",s.displayName)),oe}while(1<=l&&0<=r);break}}}finally{Fs=!1,Error.prepareStackTrace=a}return(a=s?s.displayName||s.name:"")?De(a):""}function ue(s,t){switch(s.tag){case 26:case 27:case 5:return De(s.type);case 16:return De("Lazy");case 13:return s.child!==t&&t!==null?De("Suspense Fallback"):De("Suspense");case 19:return De("SuspenseList");case 0:case 15:return Qs(s.type,!1);case 11:return Qs(s.type.render,!1);case 1:return Qs(s.type,!0);case 31:return De("Activity");default:return""}}function Ee(s){try{var t="",a=null;do t+=ue(s,a),a=s,s=s.return;while(s);return t}catch(l){return` Error generating stack: `+l.message+` -`+l.stack}}var ts=Object.prototype.hasOwnProperty,Ke=n.unstable_scheduleCallback,lt=n.unstable_cancelCallback,Ot=n.unstable_shouldYield,bt=n.unstable_requestPaint,Pe=n.unstable_now,R=n.unstable_getCurrentPriorityLevel,Re=n.unstable_ImmediatePriority,ze=n.unstable_UserBlockingPriority,$e=n.unstable_NormalPriority,Es=n.unstable_LowPriority,We=n.unstable_IdlePriority,nt=n.log,vs=n.unstable_setDisableYieldValue,ke=null,ve=null;function ns(s){if(typeof nt=="function"&&vs(s),ve&&typeof ve.setStrictMode=="function")try{ve.setStrictMode(ke,s)}catch{}}var _s=Math.clz32?Math.clz32:Ys,At=Math.log,Ps=Math.LN2;function Ys(s){return s>>>=0,s===0?32:31-(At(s)/Ps|0)|0}var Et=256,Rt=262144,Ha=4194304;function Qt(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 qa(s,t,a){var l=s.pendingLanes;if(l===0)return 0;var r=0,o=s.suspendedLanes,m=s.pingedLanes;s=s.warmLanes;var g=l&134217727;return g!==0?(l=g&~o,l!==0?r=Qt(l):(m&=g,m!==0?r=Qt(m):a||(a=g&~s,a!==0&&(r=Qt(a))))):(g=l&~o,g!==0?r=Qt(g):m!==0?r=Qt(m):a||(a=l&~s,a!==0&&(r=Qt(a)))),r===0?0:t!==0&&t!==r&&(t&o)===0&&(o=r&-r,a=t&-t,o>=a||o===32&&(a&4194048)!==0)?t:r}function Sa(s,t){return(s.pendingLanes&~(s.suspendedLanes&~s.pingedLanes)&t)===0}function ee(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 we(){var s=Ha;return Ha<<=1,(Ha&62914560)===0&&(Ha=4194304),s}function Ge(s){for(var t=[],a=0;31>a;a++)t.push(s);return t}function pt(s,t){s.pendingLanes|=t,t!==268435456&&(s.suspendedLanes=0,s.pingedLanes=0,s.warmLanes=0)}function Yt(s,t,a,l,r,o){var m=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 g=s.entanglements,E=s.expirationTimes,Z=s.hiddenUpdates;for(a=m&~a;0"u")return null;try{return s.activeElement||s.body}catch{return s.body}}var Pg=/[\n"\\]/g;function na(s){return s.replace(Pg,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function ho(s,t,a,l,r,o,m,g){s.name="",m!=null&&typeof m!="function"&&typeof m!="symbol"&&typeof m!="boolean"?s.type=m:s.removeAttribute("type"),t!=null?m==="number"?(t===0&&s.value===""||s.value!=t)&&(s.value=""+la(t)):s.value!==""+la(t)&&(s.value=""+la(t)):m!=="submit"&&m!=="reset"||s.removeAttribute("value"),t!=null?xo(s,m,la(t)):a!=null?xo(s,m,la(a)):l!=null&&s.removeAttribute("value"),r==null&&o!=null&&(s.defaultChecked=!!o),r!=null&&(s.checked=r&&typeof r!="function"&&typeof r!="symbol"),g!=null&&typeof g!="function"&&typeof g!="symbol"&&typeof g!="boolean"?s.name=""+la(g):s.removeAttribute("name")}function im(s,t,a,l,r,o,m,g){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)){mo(s);return}a=a!=null?""+la(a):"",t=t!=null?""+la(t):a,g||t===s.value||(s.value=t),s.defaultValue=t}l=l??r,l=typeof l!="function"&&typeof l!="symbol"&&!!l,s.checked=g?s.checked:!!l,s.defaultChecked=!!l,m!=null&&typeof m!="function"&&typeof m!="symbol"&&typeof m!="boolean"&&(s.name=m),mo(s)}function xo(s,t,a){t==="number"&&Tr(s.ownerDocument)===s||s.defaultValue===""+a||(s.defaultValue=""+a)}function yn(s,t,a,l){if(s=s.options,t){t={};for(var r=0;r"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),vo=!1;if(Fa)try{var pi={};Object.defineProperty(pi,"passive",{get:function(){vo=!0}}),window.addEventListener("test",pi,pi),window.removeEventListener("test",pi,pi)}catch{vo=!1}var xl=null,No=null,zr=null;function hm(){if(zr)return zr;var s,t=No,a=t.length,l,r="value"in xl?xl.value:xl.textContent,o=r.length;for(s=0;s=vi),vm=" ",Nm=!1;function bm(s,t){switch(s){case"keyup":return Cj.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ym(s){return s=s.detail,typeof s=="object"&&"data"in s?s.data:null}var Cn=!1;function Tj(s,t){switch(s){case"compositionend":return ym(t);case"keypress":return t.which!==32?null:(Nm=!0,vm);case"textInput":return s=t.data,s===vm&&Nm?null:s;default:return null}}function Ej(s,t){if(Cn)return s==="compositionend"||!So&&bm(s,t)?(s=hm(),zr=No=xl=null,Cn=!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=zm(a)}}function Mm(s,t){return s&&t?s===t?!0:s&&s.nodeType===3?!1:t&&t.nodeType===3?Mm(s,t.parentNode):"contains"in s?s.contains(t):s.compareDocumentPosition?!!(s.compareDocumentPosition(t)&16):!1:!1}function Dm(s){s=s!=null&&s.ownerDocument!=null&&s.ownerDocument.defaultView!=null?s.ownerDocument.defaultView:window;for(var t=Tr(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=Tr(s.document)}return t}function To(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 Uj=Fa&&"documentMode"in document&&11>=document.documentMode,kn=null,Eo=null,wi=null,zo=!1;function Om(s,t,a){var l=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;zo||kn==null||kn!==Tr(l)||(l=kn,"selectionStart"in l&&To(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}),wi&&yi(wi,l)||(wi=l,l=wc(Eo,"onSelect"),0>=m,r-=m,ka=1<<32-_s(t)+r|a<as?(js=Oe,Oe=null):js=Oe.sibling;var Cs=I(q,Oe,J[as],he);if(Cs===null){Oe===null&&(Oe=js);break}s&&Oe&&Cs.alternate===null&&t(q,Oe),L=o(Cs,L,as),Ss===null?Be=Cs:Ss.sibling=Cs,Ss=Cs,Oe=js}if(as===J.length)return a(q,Oe),bs&&Qa(q,as),Be;if(Oe===null){for(;asas?(js=Oe,Oe=null):js=Oe.sibling;var Ll=I(q,Oe,Cs.value,he);if(Ll===null){Oe===null&&(Oe=js);break}s&&Oe&&Ll.alternate===null&&t(q,Oe),L=o(Ll,L,as),Ss===null?Be=Ll:Ss.sibling=Ll,Ss=Ll,Oe=js}if(Cs.done)return a(q,Oe),bs&&Qa(q,as),Be;if(Oe===null){for(;!Cs.done;as++,Cs=J.next())Cs=pe(q,Cs.value,he),Cs!==null&&(L=o(Cs,L,as),Ss===null?Be=Cs:Ss.sibling=Cs,Ss=Cs);return bs&&Qa(q,as),Be}for(Oe=l(Oe);!Cs.done;as++,Cs=J.next())Cs=te(Oe,q,as,Cs.value,he),Cs!==null&&(s&&Cs.alternate!==null&&Oe.delete(Cs.key===null?as:Cs.key),L=o(Cs,L,as),Ss===null?Be=Cs:Ss.sibling=Cs,Ss=Cs);return s&&Oe.forEach(function(aN){return t(q,aN)}),bs&&Qa(q,as),Be}function Rs(q,L,J,he){if(typeof J=="object"&&J!==null&&J.type===F&&J.key===null&&(J=J.props.children),typeof J=="object"&&J!==null){switch(J.$$typeof){case C:e:{for(var Be=J.key;L!==null;){if(L.key===Be){if(Be=J.type,Be===F){if(L.tag===7){a(q,L.sibling),he=r(L,J.props.children),he.return=q,q=he;break e}}else if(L.elementType===Be||typeof Be=="object"&&Be!==null&&Be.$$typeof===D&&Wl(Be)===L.type){a(q,L.sibling),he=r(L,J.props),Ei(he,J),he.return=q,q=he;break e}a(q,L);break}else t(q,L);L=L.sibling}J.type===F?(he=Kl(J.props.children,q.mode,he,J.key),he.return=q,q=he):(he=qr(J.type,J.key,J.props,null,q.mode,he),Ei(he,J),he.return=q,q=he)}return m(q);case M:e:{for(Be=J.key;L!==null;){if(L.key===Be)if(L.tag===4&&L.stateNode.containerInfo===J.containerInfo&&L.stateNode.implementation===J.implementation){a(q,L.sibling),he=r(L,J.children||[]),he.return=q,q=he;break e}else{a(q,L);break}else t(q,L);L=L.sibling}he=Uo(J,q.mode,he),he.return=q,q=he}return m(q);case D:return J=Wl(J),Rs(q,L,J,he)}if(be(J))return Ae(q,L,J,he);if(Se(J)){if(Be=Se(J),typeof Be!="function")throw Error(d(150));return J=Be.call(J),Qe(q,L,J,he)}if(typeof J.then=="function")return Rs(q,L,Xr(J),he);if(J.$$typeof===H)return Rs(q,L,Fr(q,J),he);Kr(q,J)}return typeof J=="string"&&J!==""||typeof J=="number"||typeof J=="bigint"?(J=""+J,L!==null&&L.tag===6?(a(q,L.sibling),he=r(L,J),he.return=q,q=he):(a(q,L),he=Lo(J,q.mode,he),he.return=q,q=he),m(q)):a(q,L)}return function(q,L,J,he){try{Ti=0;var Be=Rs(q,L,J,he);return Bn=null,Be}catch(Oe){if(Oe===Un||Oe===Qr)throw Oe;var Ss=Kt(29,Oe,null,q.mode);return Ss.lanes=he,Ss.return=q,Ss}finally{}}}var sn=ah(!0),lh=ah(!1),vl=!1;function Jo(s){s.updateQueue={baseState:s.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Zo(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 Nl(s){return{lane:s,tag:0,payload:null,callback:null,next:null}}function bl(s,t,a){var l=s.updateQueue;if(l===null)return null;if(l=l.shared,(ks&2)!==0){var r=l.pending;return r===null?t.next=t:(t.next=r.next,r.next=t),l.pending=t,t=Hr(s),Gm(s,null,a),t}return Br(s,l,t,a),Hr(s)}function zi(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,hl(s,a)}}function Io(s,t){var a=s.updateQueue,l=s.alternate;if(l!==null&&(l=l.updateQueue,a===l)){var r=null,o=null;if(a=a.firstBaseUpdate,a!==null){do{var m={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};o===null?r=o=m:o=o.next=m,a=a.next}while(a!==null);o===null?r=o=t:o=o.next=t}else r=o=t;a={baseState:l.baseState,firstBaseUpdate:r,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 Po=!1;function Ai(){if(Po){var s=Ln;if(s!==null)throw s}}function Mi(s,t,a,l){Po=!1;var r=s.updateQueue;vl=!1;var o=r.firstBaseUpdate,m=r.lastBaseUpdate,g=r.shared.pending;if(g!==null){r.shared.pending=null;var E=g,Z=E.next;E.next=null,m===null?o=Z:m.next=Z,m=E;var ce=s.alternate;ce!==null&&(ce=ce.updateQueue,g=ce.lastBaseUpdate,g!==m&&(g===null?ce.firstBaseUpdate=Z:g.next=Z,ce.lastBaseUpdate=E))}if(o!==null){var pe=r.baseState;m=0,ce=Z=E=null,g=o;do{var I=g.lane&-536870913,te=I!==g.lane;if(te?(gs&I)===I:(l&I)===I){I!==0&&I===Rn&&(Po=!0),ce!==null&&(ce=ce.next={lane:0,tag:g.tag,payload:g.payload,callback:null,next:null});e:{var Ae=s,Qe=g;I=t;var Rs=a;switch(Qe.tag){case 1:if(Ae=Qe.payload,typeof Ae=="function"){pe=Ae.call(Rs,pe,I);break e}pe=Ae;break e;case 3:Ae.flags=Ae.flags&-65537|128;case 0:if(Ae=Qe.payload,I=typeof Ae=="function"?Ae.call(Rs,pe,I):Ae,I==null)break e;pe=y({},pe,I);break e;case 2:vl=!0}}I=g.callback,I!==null&&(s.flags|=64,te&&(s.flags|=8192),te=r.callbacks,te===null?r.callbacks=[I]:te.push(I))}else te={lane:I,tag:g.tag,payload:g.payload,callback:g.callback,next:null},ce===null?(Z=ce=te,E=pe):ce=ce.next=te,m|=I;if(g=g.next,g===null){if(g=r.shared.pending,g===null)break;te=g,g=te.next,te.next=null,r.lastBaseUpdate=te,r.shared.pending=null}}while(!0);ce===null&&(E=pe),r.baseState=E,r.firstBaseUpdate=Z,r.lastBaseUpdate=ce,o===null&&(r.shared.lanes=0),Cl|=m,s.lanes=m,s.memoizedState=pe}}function nh(s,t){if(typeof s!="function")throw Error(d(191,s));s.call(t)}function ih(s,t){var a=s.callbacks;if(a!==null)for(s.callbacks=null,s=0;so?o:8;var m=z.T,g={};z.T=g,gd(s,!1,t,a);try{var E=r(),Z=z.S;if(Z!==null&&Z(g,E),E!==null&&typeof E=="object"&&typeof E.then=="function"){var ce=Yj(E,l);Ri(s,t,ce,Wt(s))}else Ri(s,t,l,Wt(s))}catch(pe){Ri(s,t,{then:function(){},status:"rejected",reason:pe},Wt())}finally{X.p=o,m!==null&&g.types!==null&&(m.types=g.types),z.T=m}}function Pj(){}function fd(s,t,a,l){if(s.tag!==5)throw Error(d(476));var r=Bh(s).queue;Uh(s,r,t,k,a===null?Pj:function(){return Hh(s),a(l)})}function Bh(s){var t=s.memoizedState;if(t!==null)return t;t={memoizedState:k,baseState:k,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ja,lastRenderedState:k},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ja,lastRenderedState:a},next:null},s.memoizedState=t,s=s.alternate,s!==null&&(s.memoizedState=t),t}function Hh(s){var t=Bh(s);t.next===null&&(t=s.alternate.memoizedState),Ri(s,t.next.queue,{},Wt())}function pd(){return wt(Pi)}function qh(){return rt().memoizedState}function Gh(){return rt().memoizedState}function Wj(s){for(var t=s.return;t!==null;){switch(t.tag){case 24:case 3:var a=Wt();s=Nl(a);var l=bl(t,s,a);l!==null&&(Vt(l,t,a),zi(l,t,a)),t={cache:Qo()},s.payload=t;return}t=t.return}}function ev(s,t,a){var l=Wt();a={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},lc(s)?Fh(t,a):(a=Oo(s,t,a,l),a!==null&&(Vt(a,s,l),$h(a,t,l)))}function Vh(s,t,a){var l=Wt();Ri(s,t,a,l)}function Ri(s,t,a,l){var r={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(lc(s))Fh(t,r);else{var o=s.alternate;if(s.lanes===0&&(o===null||o.lanes===0)&&(o=t.lastRenderedReducer,o!==null))try{var m=t.lastRenderedState,g=o(m,a);if(r.hasEagerState=!0,r.eagerState=g,Xt(g,m))return Br(s,t,r,0),Us===null&&Ur(),!1}catch{}finally{}if(a=Oo(s,t,r,l),a!==null)return Vt(a,s,l),$h(a,t,l),!0}return!1}function gd(s,t,a,l){if(l={lane:2,revertLane:Jd(),gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},lc(s)){if(t)throw Error(d(479))}else t=Oo(s,a,l,2),t!==null&&Vt(t,s,2)}function lc(s){var t=s.alternate;return s===es||t!==null&&t===es}function Fh(s,t){qn=Ir=!0;var a=s.pending;a===null?t.next=t:(t.next=a.next,a.next=t),s.pending=t}function $h(s,t,a){if((a&4194048)!==0){var l=t.lanes;l&=s.pendingLanes,a|=l,t.lanes=a,hl(s,a)}}var Li={readContext:wt,use:ec,useCallback:Ws,useContext:Ws,useEffect:Ws,useImperativeHandle:Ws,useLayoutEffect:Ws,useInsertionEffect:Ws,useMemo:Ws,useReducer:Ws,useRef:Ws,useState:Ws,useDebugValue:Ws,useDeferredValue:Ws,useTransition:Ws,useSyncExternalStore:Ws,useId:Ws,useHostTransitionStatus:Ws,useFormState:Ws,useActionState:Ws,useOptimistic:Ws,useMemoCache:Ws,useCacheRefresh:Ws};Li.useEffectEvent=Ws;var Qh={readContext:wt,use:ec,useCallback:function(s,t){return Mt().memoizedState=[s,t===void 0?null:t],s},useContext:wt,useEffect:Th,useImperativeHandle:function(s,t,a){a=a!=null?a.concat([s]):null,tc(4194308,4,Mh.bind(null,t,s),a)},useLayoutEffect:function(s,t){return tc(4194308,4,s,t)},useInsertionEffect:function(s,t){tc(4,2,s,t)},useMemo:function(s,t){var a=Mt();t=t===void 0?null:t;var l=s();if(tn){ns(!0);try{s()}finally{ns(!1)}}return a.memoizedState=[l,t],l},useReducer:function(s,t,a){var l=Mt();if(a!==void 0){var r=a(t);if(tn){ns(!0);try{a(t)}finally{ns(!1)}}}else r=t;return l.memoizedState=l.baseState=r,s={pending:null,lanes:0,dispatch:null,lastRenderedReducer:s,lastRenderedState:r},l.queue=s,s=s.dispatch=ev.bind(null,es,s),[l.memoizedState,s]},useRef:function(s){var t=Mt();return s={current:s},t.memoizedState=s},useState:function(s){s=dd(s);var t=s.queue,a=Vh.bind(null,es,t);return t.dispatch=a,[s.memoizedState,a]},useDebugValue:hd,useDeferredValue:function(s,t){var a=Mt();return xd(a,s,t)},useTransition:function(){var s=dd(!1);return s=Uh.bind(null,es,s.queue,!0,!1),Mt().memoizedState=s,[!1,s]},useSyncExternalStore:function(s,t,a){var l=es,r=Mt();if(bs){if(a===void 0)throw Error(d(407));a=a()}else{if(a=t(),Us===null)throw Error(d(349));(gs&127)!==0||mh(l,t,a)}r.memoizedState=a;var o={value:a,getSnapshot:t};return r.queue=o,Th(xh.bind(null,l,o,s),[s]),l.flags|=2048,Vn(9,{destroy:void 0},hh.bind(null,l,o,a,t),null),a},useId:function(){var s=Mt(),t=Us.identifierPrefix;if(bs){var a=Ta,l=ka;a=(l&~(1<<32-_s(l)-1)).toString(32)+a,t="_"+t+"R_"+a,a=Pr++,0<\/script>",o=o.removeChild(o.firstChild);break;case"select":o=typeof l.is=="string"?m.createElement("select",{is:l.is}):m.createElement("select"),l.multiple?o.multiple=!0:l.size&&(o.size=l.size);break;default:o=typeof l.is=="string"?m.createElement(r,{is:l.is}):m.createElement(r)}}o[Je]=t,o[Ns]=l;e:for(m=t.child;m!==null;){if(m.tag===5||m.tag===6)o.appendChild(m.stateNode);else if(m.tag!==4&&m.tag!==27&&m.child!==null){m.child.return=m,m=m.child;continue}if(m===t)break e;for(;m.sibling===null;){if(m.return===null||m.return===t)break e;m=m.return}m.sibling.return=m.return,m=m.sibling}t.stateNode=o;e:switch(St(o,r,l),r){case"button":case"input":case"select":case"textarea":l=!!l.autoFocus;break e;case"img":l=!0;break e;default:l=!1}l&&Ia(t)}}return Ks(t),Ad(t,t.type,s===null?null:s.memoizedProps,t.pendingProps,a),null;case 6:if(s&&t.stateNode!=null)s.memoizedProps!==l&&Ia(t);else{if(typeof l!="string"&&t.stateNode===null)throw Error(d(166));if(s=me.current,Dn(t)){if(s=t.stateNode,a=t.memoizedProps,l=null,r=yt,r!==null)switch(r.tag){case 27:case 5:l=r.memoizedProps}s[Je]=t,s=!!(s.nodeValue===a||l!==null&&l.suppressHydrationWarning===!0||uf(s.nodeValue,a)),s||gl(t,!0)}else s=_c(s).createTextNode(l),s[Je]=t,t.stateNode=s}return Ks(t),null;case 31:if(a=t.memoizedState,s===null||s.memoizedState!==null){if(l=Dn(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[Je]=t}else Jl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ks(t),s=!1}else a=Go(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=a),s=!0;if(!s)return t.flags&256?(Zt(t),t):(Zt(t),null);if((t.flags&128)!==0)throw Error(d(558))}return Ks(t),null;case 13:if(l=t.memoizedState,s===null||s.memoizedState!==null&&s.memoizedState.dehydrated!==null){if(r=Dn(t),l!==null&&l.dehydrated!==null){if(s===null){if(!r)throw Error(d(318));if(r=t.memoizedState,r=r!==null?r.dehydrated:null,!r)throw Error(d(317));r[Je]=t}else Jl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ks(t),r=!1}else r=Go(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=r),r=!0;if(!r)return t.flags&256?(Zt(t),t):(Zt(t),null)}return Zt(t),(t.flags&128)!==0?(t.lanes=a,t):(a=l!==null,s=s!==null&&s.memoizedState!==null,a&&(l=t.child,r=null,l.alternate!==null&&l.alternate.memoizedState!==null&&l.alternate.memoizedState.cachePool!==null&&(r=l.alternate.memoizedState.cachePool.pool),o=null,l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(o=l.memoizedState.cachePool.pool),o!==r&&(l.flags|=2048)),a!==s&&a&&(t.child.flags|=8192),oc(t,t.updateQueue),Ks(t),null);case 4:return B(),s===null&&Wd(t.stateNode.containerInfo),Ks(t),null;case 10:return Xa(t.type),Ks(t),null;case 19:if(ie(it),l=t.memoizedState,l===null)return Ks(t),null;if(r=(t.flags&128)!==0,o=l.rendering,o===null)if(r)Bi(l,!1);else{if(et!==0||s!==null&&(s.flags&128)!==0)for(s=t.child;s!==null;){if(o=Zr(s),o!==null){for(t.flags|=128,Bi(l,!1),s=o.updateQueue,t.updateQueue=s,oc(t,s),t.subtreeFlags=0,s=a,a=t.child;a!==null;)Vm(a,s),a=a.sibling;return ae(it,it.current&1|2),bs&&Qa(t,l.treeForkCount),t.child}s=s.sibling}l.tail!==null&&Pe()>xc&&(t.flags|=128,r=!0,Bi(l,!1),t.lanes=4194304)}else{if(!r)if(s=Zr(o),s!==null){if(t.flags|=128,r=!0,s=s.updateQueue,t.updateQueue=s,oc(t,s),Bi(l,!0),l.tail===null&&l.tailMode==="hidden"&&!o.alternate&&!bs)return Ks(t),null}else 2*Pe()-l.renderingStartTime>xc&&a!==536870912&&(t.flags|=128,r=!0,Bi(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=Pe(),s.sibling=null,a=it.current,ae(it,r?a&1|2:a&1),bs&&Qa(t,l.treeForkCount),s):(Ks(t),null);case 22:case 23:return Zt(t),ed(),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&&(Ks(t),t.subtreeFlags&6&&(t.flags|=8192)):Ks(t),a=t.updateQueue,a!==null&&oc(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&&ie(Pl),null;case 24:return a=null,s!==null&&(a=s.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Xa(dt),Ks(t),null;case 25:return null;case 30:return null}throw Error(d(156,t.tag))}function nv(s,t){switch(Ho(t),t.tag){case 1:return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 3:return Xa(dt),B(),s=t.flags,(s&65536)!==0&&(s&128)===0?(t.flags=s&-65537|128,t):null;case 26:case 27:case 5:return Ce(t),null;case 31:if(t.memoizedState!==null){if(Zt(t),t.alternate===null)throw Error(d(340));Jl()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 13:if(Zt(t),s=t.memoizedState,s!==null&&s.dehydrated!==null){if(t.alternate===null)throw Error(d(340));Jl()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 19:return ie(it),null;case 4:return B(),null;case 10:return Xa(t.type),null;case 22:case 23:return Zt(t),ed(),s!==null&&ie(Pl),s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 24:return Xa(dt),null;case 25:return null;default:return null}}function fx(s,t){switch(Ho(t),t.tag){case 3:Xa(dt),B();break;case 26:case 27:case 5:Ce(t);break;case 4:B();break;case 31:t.memoizedState!==null&&Zt(t);break;case 13:Zt(t);break;case 19:ie(it);break;case 10:Xa(t.type);break;case 22:case 23:Zt(t),ed(),s!==null&&ie(Pl);break;case 24:Xa(dt)}}function Hi(s,t){try{var a=t.updateQueue,l=a!==null?a.lastEffect:null;if(l!==null){var r=l.next;a=r;do{if((a.tag&s)===s){l=void 0;var o=a.create,m=a.inst;l=o(),m.destroy=l}a=a.next}while(a!==r)}}catch(g){As(t,t.return,g)}}function _l(s,t,a){try{var l=t.updateQueue,r=l!==null?l.lastEffect:null;if(r!==null){var o=r.next;l=o;do{if((l.tag&s)===s){var m=l.inst,g=m.destroy;if(g!==void 0){m.destroy=void 0,r=t;var E=a,Z=g;try{Z()}catch(ce){As(r,E,ce)}}}l=l.next}while(l!==o)}}catch(ce){As(t,t.return,ce)}}function px(s){var t=s.updateQueue;if(t!==null){var a=s.stateNode;try{ih(t,a)}catch(l){As(s,s.return,l)}}}function gx(s,t,a){a.props=an(s.type,s.memoizedProps),a.state=s.memoizedState;try{a.componentWillUnmount()}catch(l){As(s,t,l)}}function qi(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(r){As(s,t,r)}}function Ea(s,t){var a=s.ref,l=s.refCleanup;if(a!==null)if(typeof l=="function")try{l()}catch(r){As(s,t,r)}finally{s.refCleanup=null,s=s.alternate,s!=null&&(s.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(r){As(s,t,r)}else a.current=null}function jx(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(r){As(s,s.return,r)}}function Md(s,t,a){try{var l=s.stateNode;kv(l,s.type,a,t),l[Ns]=t}catch(r){As(s,s.return,r)}}function vx(s){return s.tag===5||s.tag===3||s.tag===26||s.tag===27&&Al(s.type)||s.tag===4}function Dd(s){e:for(;;){for(;s.sibling===null;){if(s.return===null||vx(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&&Al(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 Od(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=Va));else if(l!==4&&(l===27&&Al(s.type)&&(a=s.stateNode,t=null),s=s.child,s!==null))for(Od(s,t,a),s=s.sibling;s!==null;)Od(s,t,a),s=s.sibling}function dc(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&&Al(s.type)&&(a=s.stateNode),s=s.child,s!==null))for(dc(s,t,a),s=s.sibling;s!==null;)dc(s,t,a),s=s.sibling}function Nx(s){var t=s.stateNode,a=s.memoizedProps;try{for(var l=s.type,r=t.attributes;r.length;)t.removeAttributeNode(r[0]);St(t,l,a),t[Je]=s,t[Ns]=a}catch(o){As(s,s.return,o)}}var Pa=!1,ht=!1,Rd=!1,bx=typeof WeakSet=="function"?WeakSet:Set,Nt=null;function iv(s,t){if(s=s.containerInfo,tu=Ac,s=Dm(s),To(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 r=l.anchorOffset,o=l.focusNode;l=l.focusOffset;try{a.nodeType,o.nodeType}catch{a=null;break e}var m=0,g=-1,E=-1,Z=0,ce=0,pe=s,I=null;s:for(;;){for(var te;pe!==a||r!==0&&pe.nodeType!==3||(g=m+r),pe!==o||l!==0&&pe.nodeType!==3||(E=m+l),pe.nodeType===3&&(m+=pe.nodeValue.length),(te=pe.firstChild)!==null;)I=pe,pe=te;for(;;){if(pe===s)break s;if(I===a&&++Z===r&&(g=m),I===o&&++ce===l&&(E=m),(te=pe.nextSibling)!==null)break;pe=I,I=pe.parentNode}pe=te}a=g===-1||E===-1?null:{start:g,end:E}}else a=null}a=a||{start:0,end:0}}else a=null;for(au={focusedElem:s,selectionRange:a},Ac=!1,Nt=t;Nt!==null;)if(t=Nt,s=t.child,(t.subtreeFlags&1028)!==0&&s!==null)s.return=t,Nt=s;else for(;Nt!==null;){switch(t=Nt,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"))),St(o,l,a),o[Je]=s,vt(o),l=o;break e;case"link":var m=Tf("link","href",r).get(l+(a.href||""));if(m){for(var g=0;gRs&&(m=Rs,Rs=Qe,Qe=m);var q=Am(g,Qe),L=Am(g,Rs);if(q&&L&&(te.rangeCount!==1||te.anchorNode!==q.node||te.anchorOffset!==q.offset||te.focusNode!==L.node||te.focusOffset!==L.offset)){var J=pe.createRange();J.setStart(q.node,q.offset),te.removeAllRanges(),Qe>Rs?(te.addRange(J),te.extend(L.node,L.offset)):(J.setEnd(L.node,L.offset),te.addRange(J))}}}}for(pe=[],te=g;te=te.parentNode;)te.nodeType===1&&pe.push({element:te,left:te.scrollLeft,top:te.scrollTop});for(typeof g.focus=="function"&&g.focus(),g=0;ga?32:a,z.T=null,a=Vd,Vd=null;var o=Tl,m=al;if(gt=0,Xn=Tl=null,al=0,(ks&6)!==0)throw Error(d(331));var g=ks;if(ks|=4,Mx(o.current),Ex(o,o.current,m,a),ks=g,Yi(0,!1),ve&&typeof ve.onPostCommitFiberRoot=="function")try{ve.onPostCommitFiberRoot(ke,o)}catch{}return!0}finally{X.p=r,z.T=l,Zx(s,t)}}function Px(s,t,a){t=ra(a,t),t=bd(s.stateNode,t,2),s=bl(s,t,2),s!==null&&(pt(s,2),za(s))}function As(s,t,a){if(s.tag===3)Px(s,s,a);else for(;t!==null;){if(t.tag===3){Px(t,s,a);break}else if(t.tag===1){var l=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof l.componentDidCatch=="function"&&(kl===null||!kl.has(l))){s=ra(a,s),a=Wh(2),l=bl(t,a,2),l!==null&&(ex(a,l,t,s),pt(l,2),za(l));break}}t=t.return}}function Yd(s,t,a){var l=s.pingCache;if(l===null){l=s.pingCache=new ov;var r=new Set;l.set(t,r)}else r=l.get(t),r===void 0&&(r=new Set,l.set(t,r));r.has(a)||(Bd=!0,r.add(a),s=xv.bind(null,s,t,a),t.then(s,s))}function xv(s,t,a){var l=s.pingCache;l!==null&&l.delete(t),s.pingedLanes|=s.suspendedLanes&a,s.warmLanes&=~a,Us===s&&(gs&a)===a&&(et===4||et===3&&(gs&62914560)===gs&&300>Pe()-hc?(ks&2)===0&&Kn(s,0):Hd|=a,Yn===gs&&(Yn=0)),za(s)}function Wx(s,t){t===0&&(t=we()),s=Xl(s,t),s!==null&&(pt(s,t),za(s))}function fv(s){var t=s.memoizedState,a=0;t!==null&&(a=t.retryLane),Wx(s,a)}function pv(s,t){var a=0;switch(s.tag){case 31:case 13:var l=s.stateNode,r=s.memoizedState;r!==null&&(a=r.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),Wx(s,a)}function gv(s,t){return Ke(s,t)}var Nc=null,Zn=null,Xd=!1,bc=!1,Kd=!1,zl=0;function za(s){s!==Zn&&s.next===null&&(Zn===null?Nc=Zn=s:Zn=Zn.next=s),bc=!0,Xd||(Xd=!0,vv())}function Yi(s,t){if(!Kd&&bc){Kd=!0;do for(var a=!1,l=Nc;l!==null;){if(s!==0){var r=l.pendingLanes;if(r===0)var o=0;else{var m=l.suspendedLanes,g=l.pingedLanes;o=(1<<31-_s(42|s)+1)-1,o&=r&~(m&~g),o=o&201326741?o&201326741|1:o?o|2:0}o!==0&&(a=!0,af(l,o))}else o=gs,o=qa(l,l===Us?o:0,l.cancelPendingCommit!==null||l.timeoutHandle!==-1),(o&3)===0||Sa(l,o)||(a=!0,af(l,o));l=l.next}while(a);Kd=!1}}function jv(){ef()}function ef(){bc=Xd=!1;var s=0;zl!==0&&Ev()&&(s=zl);for(var t=Pe(),a=null,l=Nc;l!==null;){var r=l.next,o=sf(l,t);o===0?(l.next=null,a===null?Nc=r:a.next=r,r===null&&(Zn=a)):(a=l,(s!==0||(o&3)!==0)&&(bc=!0)),l=r}gt!==0&>!==5||Yi(s),zl!==0&&(zl=0)}function sf(s,t){for(var a=s.suspendedLanes,l=s.pingedLanes,r=s.expirationTimes,o=s.pendingLanes&-62914561;0g)break;var ce=E.transferSize,pe=E.initiatorType;ce&&mf(pe)&&(E=E.responseEnd,m+=ce*(E"u"?null:document;function _f(s,t,a){var l=In;if(l&&typeof t=="string"&&t){var r=na(t);r='link[rel="'+s+'"][href="'+r+'"]',typeof a=="string"&&(r+='[crossorigin="'+a+'"]'),wf.has(r)||(wf.add(r),s={rel:s,crossOrigin:a,href:t},l.querySelector(r)===null&&(t=l.createElement("link"),St(t,"link",s),vt(t),l.head.appendChild(t)))}}function Bv(s){ll.D(s),_f("dns-prefetch",s,null)}function Hv(s,t){ll.C(s,t),_f("preconnect",s,t)}function qv(s,t,a){ll.L(s,t,a);var l=In;if(l&&s&&t){var r='link[rel="preload"][as="'+na(t)+'"]';t==="image"&&a&&a.imageSrcSet?(r+='[imagesrcset="'+na(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(r+='[imagesizes="'+na(a.imageSizes)+'"]')):r+='[href="'+na(s)+'"]';var o=r;switch(t){case"style":o=Pn(s);break;case"script":o=Wn(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(r)!==null||t==="style"&&l.querySelector(Zi(o))||t==="script"&&l.querySelector(Ii(o))||(t=l.createElement("link"),St(t,"link",s),vt(t),l.head.appendChild(t)))}}function Gv(s,t){ll.m(s,t);var a=In;if(a&&s){var l=t&&typeof t.as=="string"?t.as:"script",r='link[rel="modulepreload"][as="'+na(l)+'"][href="'+na(s)+'"]',o=r;switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":o=Wn(s)}if(!ha.has(o)&&(s=y({rel:"modulepreload",href:s},t),ha.set(o,s),a.querySelector(r)===null)){switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(Ii(o)))return}l=a.createElement("link"),St(l,"link",s),vt(l),a.head.appendChild(l)}}}function Vv(s,t,a){ll.S(s,t,a);var l=In;if(l&&s){var r=Nn(l).hoistableStyles,o=Pn(s);t=t||"default";var m=r.get(o);if(!m){var g={loading:0,preload:null};if(m=l.querySelector(Zi(o)))g.loading=5;else{s=y({rel:"stylesheet",href:s,"data-precedence":t},a),(a=ha.get(o))&&du(s,a);var E=m=l.createElement("link");vt(E),St(E,"link",s),E._p=new Promise(function(Z,ce){E.onload=Z,E.onerror=ce}),E.addEventListener("load",function(){g.loading|=1}),E.addEventListener("error",function(){g.loading|=2}),g.loading|=4,Cc(m,t,l)}m={type:"stylesheet",instance:m,count:1,state:g},r.set(o,m)}}}function Fv(s,t){ll.X(s,t);var a=In;if(a&&s){var l=Nn(a).hoistableScripts,r=Wn(s),o=l.get(r);o||(o=a.querySelector(Ii(r)),o||(s=y({src:s,async:!0},t),(t=ha.get(r))&&uu(s,t),o=a.createElement("script"),vt(o),St(o,"link",s),a.head.appendChild(o)),o={type:"script",instance:o,count:1,state:null},l.set(r,o))}}function $v(s,t){ll.M(s,t);var a=In;if(a&&s){var l=Nn(a).hoistableScripts,r=Wn(s),o=l.get(r);o||(o=a.querySelector(Ii(r)),o||(s=y({src:s,async:!0,type:"module"},t),(t=ha.get(r))&&uu(s,t),o=a.createElement("script"),vt(o),St(o,"link",s),a.head.appendChild(o)),o={type:"script",instance:o,count:1,state:null},l.set(r,o))}}function Sf(s,t,a,l){var r=(r=me.current)?Sc(r):null;if(!r)throw Error(d(446));switch(s){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=Pn(a.href),a=Nn(r).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=Pn(a.href);var o=Nn(r).hoistableStyles,m=o.get(s);if(m||(r=r.ownerDocument||r,m={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},o.set(s,m),(o=r.querySelector(Zi(s)))&&!o._p&&(m.instance=o,m.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||Qv(r,s,a,m.state))),t&&l===null)throw Error(d(528,""));return m}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=Wn(a),a=Nn(r).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 Pn(s){return'href="'+na(s)+'"'}function Zi(s){return'link[rel="stylesheet"]['+s+"]"}function Cf(s){return y({},s,{"data-precedence":s.precedence,precedence:null})}function Qv(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}),St(t,"link",a),vt(t),s.head.appendChild(t))}function Wn(s){return'[src="'+na(s)+'"]'}function Ii(s){return"script[async]"+s}function kf(s,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var l=s.querySelector('style[data-href~="'+na(a.href)+'"]');if(l)return t.instance=l,vt(l),l;var r=y({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return l=(s.ownerDocument||s).createElement("style"),vt(l),St(l,"style",r),Cc(l,a.precedence,s),t.instance=l;case"stylesheet":r=Pn(a.href);var o=s.querySelector(Zi(r));if(o)return t.state.loading|=4,t.instance=o,vt(o),o;l=Cf(a),(r=ha.get(r))&&du(l,r),o=(s.ownerDocument||s).createElement("link"),vt(o);var m=o;return m._p=new Promise(function(g,E){m.onload=g,m.onerror=E}),St(o,"link",l),t.state.loading|=4,Cc(o,a.precedence,s),t.instance=o;case"script":return o=Wn(a.src),(r=s.querySelector(Ii(o)))?(t.instance=r,vt(r),r):(l=a,(r=ha.get(o))&&(l=y({},a),uu(l,r)),s=s.ownerDocument||s,r=s.createElement("script"),vt(r),St(r,"link",l),s.head.appendChild(r),t.instance=r);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,Cc(l,a.precedence,s));return t.instance}function Cc(s,t,a){for(var l=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),r=l.length?l[l.length-1]:null,o=r,m=0;m title"):null)}function Yv(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 zf(s){return!(s.type==="stylesheet"&&(s.state.loading&3)===0)}function Xv(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 r=Pn(l.href),o=t.querySelector(Zi(r));if(o){t=o._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(s.count++,s=Tc.bind(s),t.then(s,s)),a.state.loading|=4,a.instance=o,vt(o);return}o=t.ownerDocument||t,l=Cf(l),(r=ha.get(r))&&du(l,r),o=o.createElement("link"),vt(o);var m=o;m._p=new Promise(function(g,E){m.onload=g,m.onerror=E}),St(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=Tc.bind(s),t.addEventListener("load",a),t.addEventListener("error",a))}}var mu=0;function Kv(s,t){return s.stylesheets&&s.count===0&&zc(s,s.stylesheets),0mu?50:800)+t);return s.unsuspend=a,function(){s.unsuspend=null,clearTimeout(l),clearTimeout(r)}}:null}function Tc(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)zc(this,this.stylesheets);else if(this.unsuspend){var s=this.unsuspend;this.unsuspend=null,s()}}}var Ec=null;function zc(s,t){s.stylesheets=null,s.unsuspend!==null&&(s.count++,Ec=new Map,t.forEach(Jv,s),Ec=null,Tc.call(s))}function Jv(s,t){if(!(t.state.loading&4)){var a=Ec.get(s);if(a)var l=a.get(null);else{a=new Map,Ec.set(s,a);for(var r=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(i){console.error(i)}}return n(),_u.exports=yy(),_u.exports}var _y=wy();function $(...n){return xN(fN(n))}const Ze=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("rounded-xl border bg-card text-card-foreground shadow",n),...i}));Ze.displayName="Card";const ys=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("flex flex-col space-y-1.5 p-6",n),...i}));ys.displayName="CardHeader";const ws=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("font-semibold leading-none tracking-tight",n),...i}));ws.displayName="CardTitle";const ct=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("text-sm text-muted-foreground",n),...i}));ct.displayName="CardDescription";const Ts=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("p-6 pt-0",n),...i}));Ts.displayName="CardContent";const pg=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("flex items-center p-6 pt-0",n),...i}));pg.displayName="CardFooter";const La=jN,wa=u.forwardRef(({className:n,...i},c)=>e.jsx(Np,{ref:c,className:$("inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",n),...i}));wa.displayName=Np.displayName;const fs=u.forwardRef(({className:n,...i},c)=>e.jsx(bp,{ref:c,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),...i}));fs.displayName=bp.displayName;const Ms=u.forwardRef(({className:n,...i},c)=>e.jsx(yp,{ref:c,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),...i}));Ms.displayName=yp.displayName;const ss=u.forwardRef(({className:n,children:i,viewportRef:c,...d},h)=>e.jsxs(wp,{ref:h,className:$("relative overflow-hidden",n),...d,children:[e.jsx(vN,{ref:c,className:"h-full w-full rounded-[inherit]",children:i}),e.jsx(Ru,{}),e.jsx(Ru,{orientation:"horizontal"}),e.jsx(NN,{})]}));ss.displayName=wp.displayName;const Ru=u.forwardRef(({className:n,orientation:i="vertical",...c},d)=>e.jsx(_p,{ref:d,orientation:i,className:$("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]",n),...c,children:e.jsx(bN,{className:"relative flex-1 rounded-full bg-border"})}));Ru.displayName=_p.displayName;function gg({className:n,...i}){return e.jsx("div",{className:$("animate-pulse rounded-md bg-primary/10",n),...i})}const wr=u.forwardRef(({className:n,value:i,...c},d)=>e.jsx(Sp,{ref:d,className:$("relative h-2 w-full overflow-hidden rounded-full bg-primary/20",n),...c,children:e.jsx(yN,{className:"h-full w-full flex-1 bg-primary transition-all",style:{transform:`translateX(-${100-(i||0)}%)`}})}));wr.displayName=Sp.displayName;const Sy={light:"",dark:".dark"},jg=u.createContext(null);function vg(){const n=u.useContext(jg);if(!n)throw new Error("useChart must be used within a ");return n}const si=u.forwardRef(({id:n,className:i,children:c,config:d,...h},x)=>{const f=u.useId(),j=`chart-${n||f.replace(/:/g,"")}`;return e.jsx(jg.Provider,{value:{config:d},children:e.jsxs("div",{"data-chart":j,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",i),...h,children:[e.jsx(Cy,{id:j,config:d}),e.jsx(LN,{children:c})]})})});si.displayName="Chart";const Cy=({id:n,config:i})=>{const c=Object.entries(i).filter(([,d])=>d.theme||d.color);return c.length?e.jsx("style",{dangerouslySetInnerHTML:{__html:Object.entries(Sy).map(([d,h])=>` +`+l.stack}}var as=Object.prototype.hasOwnProperty,Ke=n.unstable_scheduleCallback,lt=n.unstable_cancelCallback,Ot=n.unstable_shouldYield,bt=n.unstable_requestPaint,Pe=n.unstable_now,U=n.unstable_getCurrentPriorityLevel,Re=n.unstable_ImmediatePriority,ze=n.unstable_UserBlockingPriority,Ye=n.unstable_NormalPriority,zs=n.unstable_LowPriority,We=n.unstable_IdlePriority,nt=n.log,vs=n.unstable_setDisableYieldValue,ke=null,ve=null;function is(s){if(typeof nt=="function"&&vs(s),ve&&typeof ve.setStrictMode=="function")try{ve.setStrictMode(ke,s)}catch{}}var _s=Math.clz32?Math.clz32:Ys,At=Math.log,Ps=Math.LN2;function Ys(s){return s>>>=0,s===0?32:31-(At(s)/Ps|0)|0}var Et=256,Rt=262144,Ha=4194304;function Yt(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 qa(s,t,a){var l=s.pendingLanes;if(l===0)return 0;var r=0,o=s.suspendedLanes,m=s.pingedLanes;s=s.warmLanes;var g=l&134217727;return g!==0?(l=g&~o,l!==0?r=Yt(l):(m&=g,m!==0?r=Yt(m):a||(a=g&~s,a!==0&&(r=Yt(a))))):(g=l&~o,g!==0?r=Yt(g):m!==0?r=Yt(m):a||(a=l&~s,a!==0&&(r=Yt(a)))),r===0?0:t!==0&&t!==r&&(t&o)===0&&(o=r&-r,a=t&-t,o>=a||o===32&&(a&4194048)!==0)?t:r}function Ta(s,t){return(s.pendingLanes&~(s.suspendedLanes&~s.pingedLanes)&t)===0}function ee(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 we(){var s=Ha;return Ha<<=1,(Ha&62914560)===0&&(Ha=4194304),s}function Ve(s){for(var t=[],a=0;31>a;a++)t.push(s);return t}function pt(s,t){s.pendingLanes|=t,t!==268435456&&(s.suspendedLanes=0,s.pingedLanes=0,s.warmLanes=0)}function Xt(s,t,a,l,r,o){var m=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 g=s.entanglements,z=s.expirationTimes,Z=s.hiddenUpdates;for(a=m&~a;0"u")return null;try{return s.activeElement||s.body}catch{return s.body}}var tj=/[\n"\\]/g;function na(s){return s.replace(tj,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function ho(s,t,a,l,r,o,m,g){s.name="",m!=null&&typeof m!="function"&&typeof m!="symbol"&&typeof m!="boolean"?s.type=m:s.removeAttribute("type"),t!=null?m==="number"?(t===0&&s.value===""||s.value!=t)&&(s.value=""+la(t)):s.value!==""+la(t)&&(s.value=""+la(t)):m!=="submit"&&m!=="reset"||s.removeAttribute("value"),t!=null?xo(s,m,la(t)):a!=null?xo(s,m,la(a)):l!=null&&s.removeAttribute("value"),r==null&&o!=null&&(s.defaultChecked=!!o),r!=null&&(s.checked=r&&typeof r!="function"&&typeof r!="symbol"),g!=null&&typeof g!="function"&&typeof g!="symbol"&&typeof g!="boolean"?s.name=""+la(g):s.removeAttribute("name")}function om(s,t,a,l,r,o,m,g){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)){mo(s);return}a=a!=null?""+la(a):"",t=t!=null?""+la(t):a,g||t===s.value||(s.value=t),s.defaultValue=t}l=l??r,l=typeof l!="function"&&typeof l!="symbol"&&!!l,s.checked=g?s.checked:!!l,s.defaultChecked=!!l,m!=null&&typeof m!="function"&&typeof m!="symbol"&&typeof m!="boolean"&&(s.name=m),mo(s)}function xo(s,t,a){t==="number"&&Tr(s.ownerDocument)===s||s.defaultValue===""+a||(s.defaultValue=""+a)}function yn(s,t,a,l){if(s=s.options,t){t={};for(var r=0;r"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),vo=!1;if(Fa)try{var pi={};Object.defineProperty(pi,"passive",{get:function(){vo=!0}}),window.addEventListener("test",pi,pi),window.removeEventListener("test",pi,pi)}catch{vo=!1}var xl=null,No=null,zr=null;function pm(){if(zr)return zr;var s,t=No,a=t.length,l,r="value"in xl?xl.value:xl.textContent,o=r.length;for(s=0;s=vi),ym=" ",wm=!1;function _m(s,t){switch(s){case"keyup":return zj.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Sm(s){return s=s.detail,typeof s=="object"&&"data"in s?s.data:null}var Cn=!1;function Mj(s,t){switch(s){case"compositionend":return Sm(t);case"keypress":return t.which!==32?null:(wm=!0,ym);case"textInput":return s=t.data,s===ym&&wm?null:s;default:return null}}function Dj(s,t){if(Cn)return s==="compositionend"||!So&&_m(s,t)?(s=pm(),zr=No=xl=null,Cn=!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=Dm(a)}}function Rm(s,t){return s&&t?s===t?!0:s&&s.nodeType===3?!1:t&&t.nodeType===3?Rm(s,t.parentNode):"contains"in s?s.contains(t):s.compareDocumentPosition?!!(s.compareDocumentPosition(t)&16):!1:!1}function Lm(s){s=s!=null&&s.ownerDocument!=null&&s.ownerDocument.defaultView!=null?s.ownerDocument.defaultView:window;for(var t=Tr(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=Tr(s.document)}return t}function To(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 Gj=Fa&&"documentMode"in document&&11>=document.documentMode,kn=null,Eo=null,wi=null,zo=!1;function Um(s,t,a){var l=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;zo||kn==null||kn!==Tr(l)||(l=kn,"selectionStart"in l&&To(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}),wi&&yi(wi,l)||(wi=l,l=wc(Eo,"onSelect"),0>=m,r-=m,za=1<<32-_s(t)+r|a<ls?(js=Oe,Oe=null):js=Oe.sibling;var Cs=I(F,Oe,J[ls],xe);if(Cs===null){Oe===null&&(Oe=js);break}s&&Oe&&Cs.alternate===null&&t(F,Oe),B=o(Cs,B,ls),Ss===null?Ge=Cs:Ss.sibling=Cs,Ss=Cs,Oe=js}if(ls===J.length)return a(F,Oe),bs&&Qa(F,ls),Ge;if(Oe===null){for(;lsls?(js=Oe,Oe=null):js=Oe.sibling;var Ll=I(F,Oe,Cs.value,xe);if(Ll===null){Oe===null&&(Oe=js);break}s&&Oe&&Ll.alternate===null&&t(F,Oe),B=o(Ll,B,ls),Ss===null?Ge=Ll:Ss.sibling=Ll,Ss=Ll,Oe=js}if(Cs.done)return a(F,Oe),bs&&Qa(F,ls),Ge;if(Oe===null){for(;!Cs.done;ls++,Cs=J.next())Cs=ge(F,Cs.value,xe),Cs!==null&&(B=o(Cs,B,ls),Ss===null?Ge=Cs:Ss.sibling=Cs,Ss=Cs);return bs&&Qa(F,ls),Ge}for(Oe=l(Oe);!Cs.done;ls++,Cs=J.next())Cs=ae(Oe,F,ls,Cs.value,xe),Cs!==null&&(s&&Cs.alternate!==null&&Oe.delete(Cs.key===null?ls:Cs.key),B=o(Cs,B,ls),Ss===null?Ge=Cs:Ss.sibling=Cs,Ss=Cs);return s&&Oe.forEach(function(rN){return t(F,rN)}),bs&&Qa(F,ls),Ge}function Rs(F,B,J,xe){if(typeof J=="object"&&J!==null&&J.type===Y&&J.key===null&&(J=J.props.children),typeof J=="object"&&J!==null){switch(J.$$typeof){case k:e:{for(var Ge=J.key;B!==null;){if(B.key===Ge){if(Ge=J.type,Ge===Y){if(B.tag===7){a(F,B.sibling),xe=r(B,J.props.children),xe.return=F,F=xe;break e}}else if(B.elementType===Ge||typeof Ge=="object"&&Ge!==null&&Ge.$$typeof===M&&Wl(Ge)===B.type){a(F,B.sibling),xe=r(B,J.props),Ei(xe,J),xe.return=F,F=xe;break e}a(F,B);break}else t(F,B);B=B.sibling}J.type===Y?(xe=Kl(J.props.children,F.mode,xe,J.key),xe.return=F,F=xe):(xe=qr(J.type,J.key,J.props,null,F.mode,xe),Ei(xe,J),xe.return=F,F=xe)}return m(F);case O:e:{for(Ge=J.key;B!==null;){if(B.key===Ge)if(B.tag===4&&B.stateNode.containerInfo===J.containerInfo&&B.stateNode.implementation===J.implementation){a(F,B.sibling),xe=r(B,J.children||[]),xe.return=F,F=xe;break e}else{a(F,B);break}else t(F,B);B=B.sibling}xe=Uo(J,F.mode,xe),xe.return=F,F=xe}return m(F);case M:return J=Wl(J),Rs(F,B,J,xe)}if(be(J))return Ae(F,B,J,xe);if(Se(J)){if(Ge=Se(J),typeof Ge!="function")throw Error(d(150));return J=Ge.call(J),Xe(F,B,J,xe)}if(typeof J.then=="function")return Rs(F,B,Xr(J),xe);if(J.$$typeof===D)return Rs(F,B,Fr(F,J),xe);Kr(F,J)}return typeof J=="string"&&J!==""||typeof J=="number"||typeof J=="bigint"?(J=""+J,B!==null&&B.tag===6?(a(F,B.sibling),xe=r(B,J),xe.return=F,F=xe):(a(F,B),xe=Lo(J,F.mode,xe),xe.return=F,F=xe),m(F)):a(F,B)}return function(F,B,J,xe){try{Ti=0;var Ge=Rs(F,B,J,xe);return Bn=null,Ge}catch(Oe){if(Oe===Un||Oe===Qr)throw Oe;var Ss=Jt(29,Oe,null,F.mode);return Ss.lanes=xe,Ss.return=F,Ss}finally{}}}var sn=ih(!0),rh=ih(!1),vl=!1;function Jo(s){s.updateQueue={baseState:s.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Zo(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 Nl(s){return{lane:s,tag:0,payload:null,callback:null,next:null}}function bl(s,t,a){var l=s.updateQueue;if(l===null)return null;if(l=l.shared,(ks&2)!==0){var r=l.pending;return r===null?t.next=t:(t.next=r.next,r.next=t),l.pending=t,t=Hr(s),$m(s,null,a),t}return Br(s,l,t,a),Hr(s)}function zi(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,hl(s,a)}}function Io(s,t){var a=s.updateQueue,l=s.alternate;if(l!==null&&(l=l.updateQueue,a===l)){var r=null,o=null;if(a=a.firstBaseUpdate,a!==null){do{var m={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};o===null?r=o=m:o=o.next=m,a=a.next}while(a!==null);o===null?r=o=t:o=o.next=t}else r=o=t;a={baseState:l.baseState,firstBaseUpdate:r,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 Po=!1;function Ai(){if(Po){var s=Ln;if(s!==null)throw s}}function Mi(s,t,a,l){Po=!1;var r=s.updateQueue;vl=!1;var o=r.firstBaseUpdate,m=r.lastBaseUpdate,g=r.shared.pending;if(g!==null){r.shared.pending=null;var z=g,Z=z.next;z.next=null,m===null?o=Z:m.next=Z,m=z;var oe=s.alternate;oe!==null&&(oe=oe.updateQueue,g=oe.lastBaseUpdate,g!==m&&(g===null?oe.firstBaseUpdate=Z:g.next=Z,oe.lastBaseUpdate=z))}if(o!==null){var ge=r.baseState;m=0,oe=Z=z=null,g=o;do{var I=g.lane&-536870913,ae=I!==g.lane;if(ae?(gs&I)===I:(l&I)===I){I!==0&&I===Rn&&(Po=!0),oe!==null&&(oe=oe.next={lane:0,tag:g.tag,payload:g.payload,callback:null,next:null});e:{var Ae=s,Xe=g;I=t;var Rs=a;switch(Xe.tag){case 1:if(Ae=Xe.payload,typeof Ae=="function"){ge=Ae.call(Rs,ge,I);break e}ge=Ae;break e;case 3:Ae.flags=Ae.flags&-65537|128;case 0:if(Ae=Xe.payload,I=typeof Ae=="function"?Ae.call(Rs,ge,I):Ae,I==null)break e;ge=y({},ge,I);break e;case 2:vl=!0}}I=g.callback,I!==null&&(s.flags|=64,ae&&(s.flags|=8192),ae=r.callbacks,ae===null?r.callbacks=[I]:ae.push(I))}else ae={lane:I,tag:g.tag,payload:g.payload,callback:g.callback,next:null},oe===null?(Z=oe=ae,z=ge):oe=oe.next=ae,m|=I;if(g=g.next,g===null){if(g=r.shared.pending,g===null)break;ae=g,g=ae.next,ae.next=null,r.lastBaseUpdate=ae,r.shared.pending=null}}while(!0);oe===null&&(z=ge),r.baseState=z,r.firstBaseUpdate=Z,r.lastBaseUpdate=oe,o===null&&(r.shared.lanes=0),Cl|=m,s.lanes=m,s.memoizedState=ge}}function ch(s,t){if(typeof s!="function")throw Error(d(191,s));s.call(t)}function oh(s,t){var a=s.callbacks;if(a!==null)for(s.callbacks=null,s=0;so?o:8;var m=A.T,g={};A.T=g,gd(s,!1,t,a);try{var z=r(),Z=A.S;if(Z!==null&&Z(g,z),z!==null&&typeof z=="object"&&typeof z.then=="function"){var oe=Zj(z,l);Ri(s,t,oe,ea(s))}else Ri(s,t,l,ea(s))}catch(ge){Ri(s,t,{then:function(){},status:"rejected",reason:ge},ea())}finally{K.p=o,m!==null&&g.types!==null&&(m.types=g.types),A.T=m}}function tv(){}function fd(s,t,a,l){if(s.tag!==5)throw Error(d(476));var r=Gh(s).queue;qh(s,r,t,E,a===null?tv:function(){return Vh(s),a(l)})}function Gh(s){var t=s.memoizedState;if(t!==null)return t;t={memoizedState:E,baseState:E,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ja,lastRenderedState:E},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ja,lastRenderedState:a},next:null},s.memoizedState=t,s=s.alternate,s!==null&&(s.memoizedState=t),t}function Vh(s){var t=Gh(s);t.next===null&&(t=s.alternate.memoizedState),Ri(s,t.next.queue,{},ea())}function pd(){return wt(Pi)}function Fh(){return rt().memoizedState}function $h(){return rt().memoizedState}function av(s){for(var t=s.return;t!==null;){switch(t.tag){case 24:case 3:var a=ea();s=Nl(a);var l=bl(t,s,a);l!==null&&(Vt(l,t,a),zi(l,t,a)),t={cache:Qo()},s.payload=t;return}t=t.return}}function lv(s,t,a){var l=ea();a={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},lc(s)?Yh(t,a):(a=Oo(s,t,a,l),a!==null&&(Vt(a,s,l),Xh(a,t,l)))}function Qh(s,t,a){var l=ea();Ri(s,t,a,l)}function Ri(s,t,a,l){var r={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(lc(s))Yh(t,r);else{var o=s.alternate;if(s.lanes===0&&(o===null||o.lanes===0)&&(o=t.lastRenderedReducer,o!==null))try{var m=t.lastRenderedState,g=o(m,a);if(r.hasEagerState=!0,r.eagerState=g,Kt(g,m))return Br(s,t,r,0),Us===null&&Ur(),!1}catch{}finally{}if(a=Oo(s,t,r,l),a!==null)return Vt(a,s,l),Xh(a,t,l),!0}return!1}function gd(s,t,a,l){if(l={lane:2,revertLane:Jd(),gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},lc(s)){if(t)throw Error(d(479))}else t=Oo(s,a,l,2),t!==null&&Vt(t,s,2)}function lc(s){var t=s.alternate;return s===es||t!==null&&t===es}function Yh(s,t){qn=Ir=!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 l=t.lanes;l&=s.pendingLanes,a|=l,t.lanes=a,hl(s,a)}}var Li={readContext:wt,use:ec,useCallback:Ws,useContext:Ws,useEffect:Ws,useImperativeHandle:Ws,useLayoutEffect:Ws,useInsertionEffect:Ws,useMemo:Ws,useReducer:Ws,useRef:Ws,useState:Ws,useDebugValue:Ws,useDeferredValue:Ws,useTransition:Ws,useSyncExternalStore:Ws,useId:Ws,useHostTransitionStatus:Ws,useFormState:Ws,useActionState:Ws,useOptimistic:Ws,useMemoCache:Ws,useCacheRefresh:Ws};Li.useEffectEvent=Ws;var Kh={readContext:wt,use:ec,useCallback:function(s,t){return Mt().memoizedState=[s,t===void 0?null:t],s},useContext:wt,useEffect:Ah,useImperativeHandle:function(s,t,a){a=a!=null?a.concat([s]):null,tc(4194308,4,Rh.bind(null,t,s),a)},useLayoutEffect:function(s,t){return tc(4194308,4,s,t)},useInsertionEffect:function(s,t){tc(4,2,s,t)},useMemo:function(s,t){var a=Mt();t=t===void 0?null:t;var l=s();if(tn){is(!0);try{s()}finally{is(!1)}}return a.memoizedState=[l,t],l},useReducer:function(s,t,a){var l=Mt();if(a!==void 0){var r=a(t);if(tn){is(!0);try{a(t)}finally{is(!1)}}}else r=t;return l.memoizedState=l.baseState=r,s={pending:null,lanes:0,dispatch:null,lastRenderedReducer:s,lastRenderedState:r},l.queue=s,s=s.dispatch=lv.bind(null,es,s),[l.memoizedState,s]},useRef:function(s){var t=Mt();return s={current:s},t.memoizedState=s},useState:function(s){s=dd(s);var t=s.queue,a=Qh.bind(null,es,t);return t.dispatch=a,[s.memoizedState,a]},useDebugValue:hd,useDeferredValue:function(s,t){var a=Mt();return xd(a,s,t)},useTransition:function(){var s=dd(!1);return s=qh.bind(null,es,s.queue,!0,!1),Mt().memoizedState=s,[!1,s]},useSyncExternalStore:function(s,t,a){var l=es,r=Mt();if(bs){if(a===void 0)throw Error(d(407));a=a()}else{if(a=t(),Us===null)throw Error(d(349));(gs&127)!==0||fh(l,t,a)}r.memoizedState=a;var o={value:a,getSnapshot:t};return r.queue=o,Ah(gh.bind(null,l,o,s),[s]),l.flags|=2048,Vn(9,{destroy:void 0},ph.bind(null,l,o,a,t),null),a},useId:function(){var s=Mt(),t=Us.identifierPrefix;if(bs){var a=Aa,l=za;a=(l&~(1<<32-_s(l)-1)).toString(32)+a,t="_"+t+"R_"+a,a=Pr++,0<\/script>",o=o.removeChild(o.firstChild);break;case"select":o=typeof l.is=="string"?m.createElement("select",{is:l.is}):m.createElement("select"),l.multiple?o.multiple=!0:l.size&&(o.size=l.size);break;default:o=typeof l.is=="string"?m.createElement(r,{is:l.is}):m.createElement(r)}}o[Je]=t,o[Ns]=l;e:for(m=t.child;m!==null;){if(m.tag===5||m.tag===6)o.appendChild(m.stateNode);else if(m.tag!==4&&m.tag!==27&&m.child!==null){m.child.return=m,m=m.child;continue}if(m===t)break e;for(;m.sibling===null;){if(m.return===null||m.return===t)break e;m=m.return}m.sibling.return=m.return,m=m.sibling}t.stateNode=o;e:switch(St(o,r,l),r){case"button":case"input":case"select":case"textarea":l=!!l.autoFocus;break e;case"img":l=!0;break e;default:l=!1}l&&Ia(t)}}return Ks(t),Ad(t,t.type,s===null?null:s.memoizedProps,t.pendingProps,a),null;case 6:if(s&&t.stateNode!=null)s.memoizedProps!==l&&Ia(t);else{if(typeof l!="string"&&t.stateNode===null)throw Error(d(166));if(s=he.current,Dn(t)){if(s=t.stateNode,a=t.memoizedProps,l=null,r=yt,r!==null)switch(r.tag){case 27:case 5:l=r.memoizedProps}s[Je]=t,s=!!(s.nodeValue===a||l!==null&&l.suppressHydrationWarning===!0||xf(s.nodeValue,a)),s||gl(t,!0)}else s=_c(s).createTextNode(l),s[Je]=t,t.stateNode=s}return Ks(t),null;case 31:if(a=t.memoizedState,s===null||s.memoizedState!==null){if(l=Dn(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[Je]=t}else Jl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ks(t),s=!1}else a=Go(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=a),s=!0;if(!s)return t.flags&256?(It(t),t):(It(t),null);if((t.flags&128)!==0)throw Error(d(558))}return Ks(t),null;case 13:if(l=t.memoizedState,s===null||s.memoizedState!==null&&s.memoizedState.dehydrated!==null){if(r=Dn(t),l!==null&&l.dehydrated!==null){if(s===null){if(!r)throw Error(d(318));if(r=t.memoizedState,r=r!==null?r.dehydrated:null,!r)throw Error(d(317));r[Je]=t}else Jl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ks(t),r=!1}else r=Go(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=r),r=!0;if(!r)return t.flags&256?(It(t),t):(It(t),null)}return It(t),(t.flags&128)!==0?(t.lanes=a,t):(a=l!==null,s=s!==null&&s.memoizedState!==null,a&&(l=t.child,r=null,l.alternate!==null&&l.alternate.memoizedState!==null&&l.alternate.memoizedState.cachePool!==null&&(r=l.alternate.memoizedState.cachePool.pool),o=null,l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(o=l.memoizedState.cachePool.pool),o!==r&&(l.flags|=2048)),a!==s&&a&&(t.child.flags|=8192),oc(t,t.updateQueue),Ks(t),null);case 4:return q(),s===null&&Wd(t.stateNode.containerInfo),Ks(t),null;case 10:return Xa(t.type),Ks(t),null;case 19:if(re(it),l=t.memoizedState,l===null)return Ks(t),null;if(r=(t.flags&128)!==0,o=l.rendering,o===null)if(r)Bi(l,!1);else{if(et!==0||s!==null&&(s.flags&128)!==0)for(s=t.child;s!==null;){if(o=Zr(s),o!==null){for(t.flags|=128,Bi(l,!1),s=o.updateQueue,t.updateQueue=s,oc(t,s),t.subtreeFlags=0,s=a,a=t.child;a!==null;)Qm(a,s),a=a.sibling;return le(it,it.current&1|2),bs&&Qa(t,l.treeForkCount),t.child}s=s.sibling}l.tail!==null&&Pe()>xc&&(t.flags|=128,r=!0,Bi(l,!1),t.lanes=4194304)}else{if(!r)if(s=Zr(o),s!==null){if(t.flags|=128,r=!0,s=s.updateQueue,t.updateQueue=s,oc(t,s),Bi(l,!0),l.tail===null&&l.tailMode==="hidden"&&!o.alternate&&!bs)return Ks(t),null}else 2*Pe()-l.renderingStartTime>xc&&a!==536870912&&(t.flags|=128,r=!0,Bi(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=Pe(),s.sibling=null,a=it.current,le(it,r?a&1|2:a&1),bs&&Qa(t,l.treeForkCount),s):(Ks(t),null);case 22:case 23:return It(t),ed(),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&&(Ks(t),t.subtreeFlags&6&&(t.flags|=8192)):Ks(t),a=t.updateQueue,a!==null&&oc(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&&re(Pl),null;case 24:return a=null,s!==null&&(a=s.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Xa(ut),Ks(t),null;case 25:return null;case 30:return null}throw Error(d(156,t.tag))}function ov(s,t){switch(Ho(t),t.tag){case 1:return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 3:return Xa(ut),q(),s=t.flags,(s&65536)!==0&&(s&128)===0?(t.flags=s&-65537|128,t):null;case 26:case 27:case 5:return Ce(t),null;case 31:if(t.memoizedState!==null){if(It(t),t.alternate===null)throw Error(d(340));Jl()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 13:if(It(t),s=t.memoizedState,s!==null&&s.dehydrated!==null){if(t.alternate===null)throw Error(d(340));Jl()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 19:return re(it),null;case 4:return q(),null;case 10:return Xa(t.type),null;case 22:case 23:return It(t),ed(),s!==null&&re(Pl),s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 24:return Xa(ut),null;case 25:return null;default:return null}}function jx(s,t){switch(Ho(t),t.tag){case 3:Xa(ut),q();break;case 26:case 27:case 5:Ce(t);break;case 4:q();break;case 31:t.memoizedState!==null&&It(t);break;case 13:It(t);break;case 19:re(it);break;case 10:Xa(t.type);break;case 22:case 23:It(t),ed(),s!==null&&re(Pl);break;case 24:Xa(ut)}}function Hi(s,t){try{var a=t.updateQueue,l=a!==null?a.lastEffect:null;if(l!==null){var r=l.next;a=r;do{if((a.tag&s)===s){l=void 0;var o=a.create,m=a.inst;l=o(),m.destroy=l}a=a.next}while(a!==r)}}catch(g){Ms(t,t.return,g)}}function _l(s,t,a){try{var l=t.updateQueue,r=l!==null?l.lastEffect:null;if(r!==null){var o=r.next;l=o;do{if((l.tag&s)===s){var m=l.inst,g=m.destroy;if(g!==void 0){m.destroy=void 0,r=t;var z=a,Z=g;try{Z()}catch(oe){Ms(r,z,oe)}}}l=l.next}while(l!==o)}}catch(oe){Ms(t,t.return,oe)}}function vx(s){var t=s.updateQueue;if(t!==null){var a=s.stateNode;try{oh(t,a)}catch(l){Ms(s,s.return,l)}}}function Nx(s,t,a){a.props=an(s.type,s.memoizedProps),a.state=s.memoizedState;try{a.componentWillUnmount()}catch(l){Ms(s,t,l)}}function qi(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(r){Ms(s,t,r)}}function Ma(s,t){var a=s.ref,l=s.refCleanup;if(a!==null)if(typeof l=="function")try{l()}catch(r){Ms(s,t,r)}finally{s.refCleanup=null,s=s.alternate,s!=null&&(s.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(r){Ms(s,t,r)}else a.current=null}function bx(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(r){Ms(s,s.return,r)}}function Md(s,t,a){try{var l=s.stateNode;Av(l,s.type,a,t),l[Ns]=t}catch(r){Ms(s,s.return,r)}}function yx(s){return s.tag===5||s.tag===3||s.tag===26||s.tag===27&&Al(s.type)||s.tag===4}function Dd(s){e:for(;;){for(;s.sibling===null;){if(s.return===null||yx(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&&Al(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 Od(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=Va));else if(l!==4&&(l===27&&Al(s.type)&&(a=s.stateNode,t=null),s=s.child,s!==null))for(Od(s,t,a),s=s.sibling;s!==null;)Od(s,t,a),s=s.sibling}function dc(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&&Al(s.type)&&(a=s.stateNode),s=s.child,s!==null))for(dc(s,t,a),s=s.sibling;s!==null;)dc(s,t,a),s=s.sibling}function wx(s){var t=s.stateNode,a=s.memoizedProps;try{for(var l=s.type,r=t.attributes;r.length;)t.removeAttributeNode(r[0]);St(t,l,a),t[Je]=s,t[Ns]=a}catch(o){Ms(s,s.return,o)}}var Pa=!1,xt=!1,Rd=!1,_x=typeof WeakSet=="function"?WeakSet:Set,Nt=null;function dv(s,t){if(s=s.containerInfo,tu=Ac,s=Lm(s),To(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 r=l.anchorOffset,o=l.focusNode;l=l.focusOffset;try{a.nodeType,o.nodeType}catch{a=null;break e}var m=0,g=-1,z=-1,Z=0,oe=0,ge=s,I=null;s:for(;;){for(var ae;ge!==a||r!==0&&ge.nodeType!==3||(g=m+r),ge!==o||l!==0&&ge.nodeType!==3||(z=m+l),ge.nodeType===3&&(m+=ge.nodeValue.length),(ae=ge.firstChild)!==null;)I=ge,ge=ae;for(;;){if(ge===s)break s;if(I===a&&++Z===r&&(g=m),I===o&&++oe===l&&(z=m),(ae=ge.nextSibling)!==null)break;ge=I,I=ge.parentNode}ge=ae}a=g===-1||z===-1?null:{start:g,end:z}}else a=null}a=a||{start:0,end:0}}else a=null;for(au={focusedElem:s,selectionRange:a},Ac=!1,Nt=t;Nt!==null;)if(t=Nt,s=t.child,(t.subtreeFlags&1028)!==0&&s!==null)s.return=t,Nt=s;else for(;Nt!==null;){switch(t=Nt,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"))),St(o,l,a),o[Je]=s,vt(o),l=o;break e;case"link":var m=Af("link","href",r).get(l+(a.href||""));if(m){for(var g=0;gRs&&(m=Rs,Rs=Xe,Xe=m);var F=Om(g,Xe),B=Om(g,Rs);if(F&&B&&(ae.rangeCount!==1||ae.anchorNode!==F.node||ae.anchorOffset!==F.offset||ae.focusNode!==B.node||ae.focusOffset!==B.offset)){var J=ge.createRange();J.setStart(F.node,F.offset),ae.removeAllRanges(),Xe>Rs?(ae.addRange(J),ae.extend(B.node,B.offset)):(J.setEnd(B.node,B.offset),ae.addRange(J))}}}}for(ge=[],ae=g;ae=ae.parentNode;)ae.nodeType===1&&ge.push({element:ae,left:ae.scrollLeft,top:ae.scrollTop});for(typeof g.focus=="function"&&g.focus(),g=0;ga?32:a,A.T=null,a=Vd,Vd=null;var o=Tl,m=al;if(gt=0,Xn=Tl=null,al=0,(ks&6)!==0)throw Error(d(331));var g=ks;if(ks|=4,Rx(o.current),Mx(o,o.current,m,a),ks=g,Yi(0,!1),ve&&typeof ve.onPostCommitFiberRoot=="function")try{ve.onPostCommitFiberRoot(ke,o)}catch{}return!0}finally{K.p=r,A.T=l,Wx(s,t)}}function sf(s,t,a){t=ra(a,t),t=bd(s.stateNode,t,2),s=bl(s,t,2),s!==null&&(pt(s,2),Da(s))}function Ms(s,t,a){if(s.tag===3)sf(s,s,a);else for(;t!==null;){if(t.tag===3){sf(t,s,a);break}else if(t.tag===1){var l=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof l.componentDidCatch=="function"&&(kl===null||!kl.has(l))){s=ra(a,s),a=tx(2),l=bl(t,a,2),l!==null&&(ax(a,l,t,s),pt(l,2),Da(l));break}}t=t.return}}function Yd(s,t,a){var l=s.pingCache;if(l===null){l=s.pingCache=new hv;var r=new Set;l.set(t,r)}else r=l.get(t),r===void 0&&(r=new Set,l.set(t,r));r.has(a)||(Bd=!0,r.add(a),s=jv.bind(null,s,t,a),t.then(s,s))}function jv(s,t,a){var l=s.pingCache;l!==null&&l.delete(t),s.pingedLanes|=s.suspendedLanes&a,s.warmLanes&=~a,Us===s&&(gs&a)===a&&(et===4||et===3&&(gs&62914560)===gs&&300>Pe()-hc?(ks&2)===0&&Kn(s,0):Hd|=a,Yn===gs&&(Yn=0)),Da(s)}function tf(s,t){t===0&&(t=we()),s=Xl(s,t),s!==null&&(pt(s,t),Da(s))}function vv(s){var t=s.memoizedState,a=0;t!==null&&(a=t.retryLane),tf(s,a)}function Nv(s,t){var a=0;switch(s.tag){case 31:case 13:var l=s.stateNode,r=s.memoizedState;r!==null&&(a=r.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),tf(s,a)}function bv(s,t){return Ke(s,t)}var Nc=null,Zn=null,Xd=!1,bc=!1,Kd=!1,zl=0;function Da(s){s!==Zn&&s.next===null&&(Zn===null?Nc=Zn=s:Zn=Zn.next=s),bc=!0,Xd||(Xd=!0,wv())}function Yi(s,t){if(!Kd&&bc){Kd=!0;do for(var a=!1,l=Nc;l!==null;){if(s!==0){var r=l.pendingLanes;if(r===0)var o=0;else{var m=l.suspendedLanes,g=l.pingedLanes;o=(1<<31-_s(42|s)+1)-1,o&=r&~(m&~g),o=o&201326741?o&201326741|1:o?o|2:0}o!==0&&(a=!0,rf(l,o))}else o=gs,o=qa(l,l===Us?o:0,l.cancelPendingCommit!==null||l.timeoutHandle!==-1),(o&3)===0||Ta(l,o)||(a=!0,rf(l,o));l=l.next}while(a);Kd=!1}}function yv(){af()}function af(){bc=Xd=!1;var s=0;zl!==0&&Dv()&&(s=zl);for(var t=Pe(),a=null,l=Nc;l!==null;){var r=l.next,o=lf(l,t);o===0?(l.next=null,a===null?Nc=r:a.next=r,r===null&&(Zn=a)):(a=l,(s!==0||(o&3)!==0)&&(bc=!0)),l=r}gt!==0&>!==5||Yi(s),zl!==0&&(zl=0)}function lf(s,t){for(var a=s.suspendedLanes,l=s.pingedLanes,r=s.expirationTimes,o=s.pendingLanes&-62914561;0g)break;var oe=z.transferSize,ge=z.initiatorType;oe&&ff(ge)&&(z=z.responseEnd,m+=oe*(z"u"?null:document;function kf(s,t,a){var l=In;if(l&&typeof t=="string"&&t){var r=na(t);r='link[rel="'+s+'"][href="'+r+'"]',typeof a=="string"&&(r+='[crossorigin="'+a+'"]'),Cf.has(r)||(Cf.add(r),s={rel:s,crossOrigin:a,href:t},l.querySelector(r)===null&&(t=l.createElement("link"),St(t,"link",s),vt(t),l.head.appendChild(t)))}}function Vv(s){ll.D(s),kf("dns-prefetch",s,null)}function Fv(s,t){ll.C(s,t),kf("preconnect",s,t)}function $v(s,t,a){ll.L(s,t,a);var l=In;if(l&&s&&t){var r='link[rel="preload"][as="'+na(t)+'"]';t==="image"&&a&&a.imageSrcSet?(r+='[imagesrcset="'+na(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(r+='[imagesizes="'+na(a.imageSizes)+'"]')):r+='[href="'+na(s)+'"]';var o=r;switch(t){case"style":o=Pn(s);break;case"script":o=Wn(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(r)!==null||t==="style"&&l.querySelector(Zi(o))||t==="script"&&l.querySelector(Ii(o))||(t=l.createElement("link"),St(t,"link",s),vt(t),l.head.appendChild(t)))}}function Qv(s,t){ll.m(s,t);var a=In;if(a&&s){var l=t&&typeof t.as=="string"?t.as:"script",r='link[rel="modulepreload"][as="'+na(l)+'"][href="'+na(s)+'"]',o=r;switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":o=Wn(s)}if(!ha.has(o)&&(s=y({rel:"modulepreload",href:s},t),ha.set(o,s),a.querySelector(r)===null)){switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(Ii(o)))return}l=a.createElement("link"),St(l,"link",s),vt(l),a.head.appendChild(l)}}}function Yv(s,t,a){ll.S(s,t,a);var l=In;if(l&&s){var r=Nn(l).hoistableStyles,o=Pn(s);t=t||"default";var m=r.get(o);if(!m){var g={loading:0,preload:null};if(m=l.querySelector(Zi(o)))g.loading=5;else{s=y({rel:"stylesheet",href:s,"data-precedence":t},a),(a=ha.get(o))&&du(s,a);var z=m=l.createElement("link");vt(z),St(z,"link",s),z._p=new Promise(function(Z,oe){z.onload=Z,z.onerror=oe}),z.addEventListener("load",function(){g.loading|=1}),z.addEventListener("error",function(){g.loading|=2}),g.loading|=4,Cc(m,t,l)}m={type:"stylesheet",instance:m,count:1,state:g},r.set(o,m)}}}function Xv(s,t){ll.X(s,t);var a=In;if(a&&s){var l=Nn(a).hoistableScripts,r=Wn(s),o=l.get(r);o||(o=a.querySelector(Ii(r)),o||(s=y({src:s,async:!0},t),(t=ha.get(r))&&uu(s,t),o=a.createElement("script"),vt(o),St(o,"link",s),a.head.appendChild(o)),o={type:"script",instance:o,count:1,state:null},l.set(r,o))}}function Kv(s,t){ll.M(s,t);var a=In;if(a&&s){var l=Nn(a).hoistableScripts,r=Wn(s),o=l.get(r);o||(o=a.querySelector(Ii(r)),o||(s=y({src:s,async:!0,type:"module"},t),(t=ha.get(r))&&uu(s,t),o=a.createElement("script"),vt(o),St(o,"link",s),a.head.appendChild(o)),o={type:"script",instance:o,count:1,state:null},l.set(r,o))}}function Tf(s,t,a,l){var r=(r=he.current)?Sc(r):null;if(!r)throw Error(d(446));switch(s){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=Pn(a.href),a=Nn(r).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=Pn(a.href);var o=Nn(r).hoistableStyles,m=o.get(s);if(m||(r=r.ownerDocument||r,m={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},o.set(s,m),(o=r.querySelector(Zi(s)))&&!o._p&&(m.instance=o,m.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||Jv(r,s,a,m.state))),t&&l===null)throw Error(d(528,""));return m}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=Wn(a),a=Nn(r).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 Pn(s){return'href="'+na(s)+'"'}function Zi(s){return'link[rel="stylesheet"]['+s+"]"}function Ef(s){return y({},s,{"data-precedence":s.precedence,precedence:null})}function Jv(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}),St(t,"link",a),vt(t),s.head.appendChild(t))}function Wn(s){return'[src="'+na(s)+'"]'}function Ii(s){return"script[async]"+s}function zf(s,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var l=s.querySelector('style[data-href~="'+na(a.href)+'"]');if(l)return t.instance=l,vt(l),l;var r=y({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return l=(s.ownerDocument||s).createElement("style"),vt(l),St(l,"style",r),Cc(l,a.precedence,s),t.instance=l;case"stylesheet":r=Pn(a.href);var o=s.querySelector(Zi(r));if(o)return t.state.loading|=4,t.instance=o,vt(o),o;l=Ef(a),(r=ha.get(r))&&du(l,r),o=(s.ownerDocument||s).createElement("link"),vt(o);var m=o;return m._p=new Promise(function(g,z){m.onload=g,m.onerror=z}),St(o,"link",l),t.state.loading|=4,Cc(o,a.precedence,s),t.instance=o;case"script":return o=Wn(a.src),(r=s.querySelector(Ii(o)))?(t.instance=r,vt(r),r):(l=a,(r=ha.get(o))&&(l=y({},a),uu(l,r)),s=s.ownerDocument||s,r=s.createElement("script"),vt(r),St(r,"link",l),s.head.appendChild(r),t.instance=r);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,Cc(l,a.precedence,s));return t.instance}function Cc(s,t,a){for(var l=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),r=l.length?l[l.length-1]:null,o=r,m=0;m title"):null)}function Zv(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 Df(s){return!(s.type==="stylesheet"&&(s.state.loading&3)===0)}function Iv(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 r=Pn(l.href),o=t.querySelector(Zi(r));if(o){t=o._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(s.count++,s=Tc.bind(s),t.then(s,s)),a.state.loading|=4,a.instance=o,vt(o);return}o=t.ownerDocument||t,l=Ef(l),(r=ha.get(r))&&du(l,r),o=o.createElement("link"),vt(o);var m=o;m._p=new Promise(function(g,z){m.onload=g,m.onerror=z}),St(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=Tc.bind(s),t.addEventListener("load",a),t.addEventListener("error",a))}}var mu=0;function Pv(s,t){return s.stylesheets&&s.count===0&&zc(s,s.stylesheets),0mu?50:800)+t);return s.unsuspend=a,function(){s.unsuspend=null,clearTimeout(l),clearTimeout(r)}}:null}function Tc(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)zc(this,this.stylesheets);else if(this.unsuspend){var s=this.unsuspend;this.unsuspend=null,s()}}}var Ec=null;function zc(s,t){s.stylesheets=null,s.unsuspend!==null&&(s.count++,Ec=new Map,t.forEach(Wv,s),Ec=null,Tc.call(s))}function Wv(s,t){if(!(t.state.loading&4)){var a=Ec.get(s);if(a)var l=a.get(null);else{a=new Map,Ec.set(s,a);for(var r=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(i){console.error(i)}}return n(),_u.exports=Cy(),_u.exports}var Ty=ky();function X(...n){return jN(vN(n))}const Ze=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("rounded-xl border bg-card text-card-foreground shadow",n),...i}));Ze.displayName="Card";const ys=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("flex flex-col space-y-1.5 p-6",n),...i}));ys.displayName="CardHeader";const ws=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("font-semibold leading-none tracking-tight",n),...i}));ws.displayName="CardTitle";const ct=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("text-sm text-muted-foreground",n),...i}));ct.displayName="CardDescription";const Ts=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("p-6 pt-0",n),...i}));Ts.displayName="CardContent";const vg=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("flex items-center p-6 pt-0",n),...i}));vg.displayName="CardFooter";const Ca=yN,pa=u.forwardRef(({className:n,...i},c)=>e.jsx(wp,{ref:c,className:X("inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",n),...i}));pa.displayName=wp.displayName;const ns=u.forwardRef(({className:n,...i},c)=>e.jsx(_p,{ref:c,className:X("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),...i}));ns.displayName=_p.displayName;const Es=u.forwardRef(({className:n,...i},c)=>e.jsx(Sp,{ref:c,className:X("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),...i}));Es.displayName=Sp.displayName;const ss=u.forwardRef(({className:n,children:i,viewportRef:c,...d},h)=>e.jsxs(Cp,{ref:h,className:X("relative overflow-hidden",n),...d,children:[e.jsx(wN,{ref:c,className:"h-full w-full rounded-[inherit]",children:i}),e.jsx(Bu,{}),e.jsx(Bu,{orientation:"horizontal"}),e.jsx(_N,{})]}));ss.displayName=Cp.displayName;const Bu=u.forwardRef(({className:n,orientation:i="vertical",...c},d)=>e.jsx(kp,{ref:d,orientation:i,className:X("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]",n),...c,children:e.jsx(SN,{className:"relative flex-1 rounded-full bg-border"})}));Bu.displayName=kp.displayName;function Ng({className:n,...i}){return e.jsx("div",{className:X("animate-pulse rounded-md bg-primary/10",n),...i})}const wr=u.forwardRef(({className:n,value:i,...c},d)=>e.jsx(Tp,{ref:d,className:X("relative h-2 w-full overflow-hidden rounded-full bg-primary/20",n),...c,children:e.jsx(CN,{className:"h-full w-full flex-1 bg-primary transition-all",style:{transform:`translateX(-${100-(i||0)}%)`}})}));wr.displayName=Tp.displayName;const Ey={light:"",dark:".dark"},bg=u.createContext(null);function yg(){const n=u.useContext(bg);if(!n)throw new Error("useChart must be used within a ");return n}const si=u.forwardRef(({id:n,className:i,children:c,config:d,...h},f)=>{const x=u.useId(),j=`chart-${n||x.replace(/:/g,"")}`;return e.jsx(bg.Provider,{value:{config:d},children:e.jsxs("div",{"data-chart":j,ref:f,className:X("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),...h,children:[e.jsx(zy,{id:j,config:d}),e.jsx(qN,{children:c})]})})});si.displayName="Chart";const zy=({id:n,config:i})=>{const c=Object.entries(i).filter(([,d])=>d.theme||d.color);return c.length?e.jsx("style",{dangerouslySetInnerHTML:{__html:Object.entries(Ey).map(([d,h])=>` ${h} [data-chart=${n}] { -${c.map(([x,f])=>{const j=f.theme?.[d]||f.color;return j?` --color-${x}: ${j};`:null}).join(` +${c.map(([f,x])=>{const j=x.theme?.[d]||x.color;return j?` --color-${f}: ${j};`:null}).join(` `)} } `).join(` -`)}}):null},ir=UN,ti=u.forwardRef(({active:n,payload:i,className:c,indicator:d="dot",hideLabel:h=!1,hideIndicator:x=!1,label:f,labelFormatter:j,labelClassName:p,formatter:w,color:v,nameKey:y,labelKey:S},C)=>{const{config:M}=vg(),F=u.useMemo(()=>{if(h||!i?.length)return null;const[O]=i,K=`${S||O?.dataKey||O?.name||"value"}`,H=Lu(M,O,K),A=!S&&typeof f=="string"?M[f]?.label||f:H?.label;return j?e.jsx("div",{className:$("font-medium",p),children:j(A,i)}):A?e.jsx("div",{className:$("font-medium",p),children:A}):null},[f,j,i,h,p,M,S]);if(!n||!i?.length)return null;const U=i.length===1&&d!=="dot";return e.jsxs("div",{ref:C,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",c),children:[U?null:F,e.jsx("div",{className:"grid gap-1.5",children:i.filter(O=>O.type!=="none").map((O,K)=>{const H=`${y||O.name||O.dataKey||"value"}`,A=Lu(M,O,H),V=v||O.payload.fill||O.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:w&&O?.value!==void 0&&O.name?w(O.value,O.name,O,K,O.payload):e.jsxs(e.Fragment,{children:[A?.icon?e.jsx(A.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":U&&d==="dashed"}),style:{"--color-bg":V,"--color-border":V}}),e.jsxs("div",{className:$("flex flex-1 justify-between leading-none",U?"items-end":"items-center"),children:[e.jsxs("div",{className:"grid gap-1.5",children:[U?F:null,e.jsx("span",{className:"text-muted-foreground",children:A?.label||O.name})]}),O.value&&e.jsx("span",{className:"font-mono font-medium tabular-nums text-foreground",children:O.value.toLocaleString()})]})]})},O.dataKey)})})]})});ti.displayName="ChartTooltip";const ky=BN,Ng=u.forwardRef(({className:n,hideIcon:i=!1,payload:c,verticalAlign:d="bottom",nameKey:h},x)=>{const{config:f}=vg();return c?.length?e.jsx("div",{ref:x,className:$("flex items-center justify-center gap-4",d==="top"?"pb-3":"pt-3",n),children:c.filter(j=>j.type!=="none").map(j=>{const p=`${h||j.dataKey||"value"}`,w=Lu(f,j,p);return e.jsxs("div",{className:$("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"),children:[w?.icon&&!i?e.jsx(w.icon,{}):e.jsx("div",{className:"h-2 w-2 shrink-0 rounded-[2px]",style:{backgroundColor:j.color}}),w?.label]},j.value)})}):null});Ng.displayName="ChartLegend";function Lu(n,i,c){if(typeof i!="object"||i===null)return;const d="payload"in i&&typeof i.payload=="object"&&i.payload!==null?i.payload:void 0;let h=c;return c in i&&typeof i[c]=="string"?h=i[c]:d&&c in d&&typeof d[c]=="string"&&(h=d[c]),h in n?n[h]:n[c]}const gr=ci("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"}}),N=u.forwardRef(({className:n,variant:i,size:c,asChild:d=!1,...h},x)=>{const f=d?$N:"button";return e.jsx(f,{className:$(gr({variant:i,size:c,className:n})),ref:x,...h})});N.displayName="Button";const Ty=ci("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:n,variant:i,...c}){return e.jsx("div",{className:$(Ty({variant:i}),n),...c})}const Ey=5,zy=5e3;let ku=0;function Ay(){return ku=(ku+1)%Number.MAX_SAFE_INTEGER,ku.toString()}const Tu=new Map,ep=n=>{if(Tu.has(n))return;const i=setTimeout(()=>{Tu.delete(n),hr({type:"REMOVE_TOAST",toastId:n})},zy);Tu.set(n,i)},My=(n,i)=>{switch(i.type){case"ADD_TOAST":return{...n,toasts:[i.toast,...n.toasts].slice(0,Ey)};case"UPDATE_TOAST":return{...n,toasts:n.toasts.map(c=>c.id===i.toast.id?{...c,...i.toast}:c)};case"DISMISS_TOAST":{const{toastId:c}=i;return c?ep(c):n.toasts.forEach(d=>{ep(d.id)}),{...n,toasts:n.toasts.map(d=>d.id===c||c===void 0?{...d,open:!1}:d)}}case"REMOVE_TOAST":return i.toastId===void 0?{...n,toasts:[]}:{...n,toasts:n.toasts.filter(c=>c.id!==i.toastId)}}},Kc=[];let Jc={toasts:[]};function hr(n){Jc=My(Jc,n),Kc.forEach(i=>{i(Jc)})}function Dy({...n}){const i=Ay(),c=h=>hr({type:"UPDATE_TOAST",toast:{...h,id:i}}),d=()=>hr({type:"DISMISS_TOAST",toastId:i});return hr({type:"ADD_TOAST",toast:{...n,id:i,open:!0,onOpenChange:h=>{h||d()}}}),{id:i,dismiss:d,update:c}}function Gs(){const[n,i]=u.useState(Jc);return u.useEffect(()=>(Kc.push(i),()=>{const c=Kc.indexOf(i);c>-1&&Kc.splice(c,1)}),[n]),{...n,toast:Dy,dismiss:c=>hr({type:"DISMISS_TOAST",toastId:c})}}const Oy=n=>{const i=[];for(let c=0;c{try{C(!0);const k=await Bc.get("https://v1.hitokoto.cn/?c=a&c=b&c=c&c=d&c=h&c=i&c=k");y({hitokoto:k.data.hitokoto,from:k.data.from||k.data.from_who||"未知"})}catch(k){console.error("获取一言失败:",k),y({hitokoto:"人生就像一盒巧克力,你永远不知道下一颗是什么味道。",from:"阿甘正传"})}finally{C(!1)}},[]),A=u.useCallback(async()=>{try{const k=localStorage.getItem("access-token"),se=await Bc.get("/api/webui/system/status",{headers:{Authorization:`Bearer ${k}`}});F(se.data)}catch(k){console.error("获取机器人状态失败:",k),F(null)}},[]),V=async()=>{if(!U)try{O(!0);const k=localStorage.getItem("access-token");await Bc.post("/api/webui/system/restart",{},{headers:{Authorization:`Bearer ${k}`}}),K({title:"重启中",description:"麦麦正在重启,请稍候..."}),setTimeout(()=>{A(),O(!1)},3e3)}catch(k){console.error("重启失败:",k),K({title:"重启失败",description:"无法重启麦麦,请检查控制台",variant:"destructive"}),O(!1)}},Q=u.useCallback(async()=>{try{const k=localStorage.getItem("access-token"),se=await Bc.get(`/api/webui/statistics/dashboard?hours=${f}`,{headers:{Authorization:`Bearer ${k}`}});i(se.data),d(!1),x(100)}catch(k){console.error("Failed to fetch dashboard data:",k),d(!1),x(100)}},[f]);if(u.useEffect(()=>{if(!c)return;x(0);const k=setTimeout(()=>x(15),200),se=setTimeout(()=>x(30),800),_=setTimeout(()=>x(45),2e3),ue=setTimeout(()=>x(60),4e3),ie=setTimeout(()=>x(75),6500),ae=setTimeout(()=>x(85),9e3),fe=setTimeout(()=>x(92),11e3);return()=>{clearTimeout(k),clearTimeout(se),clearTimeout(_),clearTimeout(ue),clearTimeout(ie),clearTimeout(ae),clearTimeout(fe)}},[c]),u.useEffect(()=>{Q(),H(),A()},[Q,H,A]),u.useEffect(()=>{if(!p)return;const k=setInterval(()=>{Q(),A()},3e4);return()=>clearInterval(k)},[p,Q,A]),c||!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(Ct,{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(wr,{value:h,className:"h-2"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[h,"%"]})]})]})});const{summary:T,model_stats:D=[],hourly_data:ne=[],daily_data:xe=[],recent_activity:_e=[]}=n,Se=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},ge=k=>{const se=Math.floor(k/3600),_=Math.floor(k%3600/60);return`${se}小时${_}分钟`},ye=k=>new Date(k).toLocaleString("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),be=Oy(D.length),z=D.map((k,se)=>({name:k.model_name,value:k.request_count,fill:be[se]})),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(ss,{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(La,{value:f.toString(),onValueChange:k=>j(Number(k)),children:e.jsxs(wa,{className:"grid grid-cols-3 w-full sm:w-auto",children:[e.jsx(fs,{value:"24",children:"24小时"}),e.jsx(fs,{value:"168",children:"7天"}),e.jsx(fs,{value:"720",children:"30天"})]})}),e.jsxs(N,{variant:p?"default":"outline",size:"sm",onClick:()=>w(!p),className:"gap-2",children:[e.jsx(Ct,{className:`h-4 w-4 ${p?"animate-spin":""}`}),e.jsx("span",{className:"hidden sm:inline",children:"自动刷新"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:Q,children:e.jsx(Ct,{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:[S?e.jsx(gg,{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(N,{variant:"ghost",size:"icon",className:"h-7 w-7 shrink-0",onClick:H,disabled:S,children:e.jsx(Ct,{className:`h-3.5 w-3.5 ${S?"animate-spin":""}`})})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-3",children:[e.jsxs(Ze,{className:"lg:col-span-1",children:[e.jsx(ys,{className:"pb-3",children:e.jsxs(ws,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(br,{className:"h-4 w-4"}),"麦麦状态"]})}),e.jsx(Ts,{children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("div",{className:"flex items-center gap-2",children:M?.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(fa,{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(Oa,{className:"h-3 w-3 mr-1"}),"已停止"]})]})}),M&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:[e.jsxs("span",{children:["v",M.version]}),e.jsx("span",{className:"mx-2",children:"|"}),e.jsxs("span",{children:["运行 ",ge(M.uptime)]})]})]})})]}),e.jsxs(Ze,{className:"lg:col-span-2",children:[e.jsx(ys,{className:"pb-3",children:e.jsxs(ws,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(cn,{className:"h-4 w-4"}),"快速操作"]})}),e.jsx(Ts,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:V,disabled:U,className:"gap-2",children:[e.jsx(Zc,{className:`h-4 w-4 ${U?"animate-spin":""}`}),U?"重启中...":"重启麦麦"]}),e.jsx(N,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Yc,{to:"/logs",children:[e.jsx(Da,{className:"h-4 w-4"}),"查看日志"]})}),e.jsx(N,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Yc,{to:"/plugins",children:[e.jsx(cb,{className:"h-4 w-4"}),"插件管理"]})}),e.jsx(N,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Yc,{to:"/settings",children:[e.jsx(oi,{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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"总请求数"}),e.jsx(ob,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-2xl font-bold",children:Se.total_requests.toLocaleString()}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["最近",f<48?f+"小时":Math.floor(f/24)+"天"]})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"总花费"}),e.jsx(db,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:["¥",Se.total_cost.toFixed(2)]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:Se.cost_per_hour>0?`¥${Se.cost_per_hour.toFixed(2)}/小时`:"暂无数据"})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"Token消耗"}),e.jsx(Ic,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[(Se.total_tokens/1e3).toFixed(1),"K"]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:Se.tokens_per_hour>0?`${(Se.tokens_per_hour/1e3).toFixed(1)}K/小时`:"暂无数据"})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"平均响应"}),e.jsx(cn,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[Se.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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"在线时长"}),e.jsx(li,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(Ts,{children:e.jsx("div",{className:"text-xl font-bold",children:ge(Se.online_time)})})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"消息处理"}),e.jsx(un,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-xl font-bold",children:Se.total_messages.toLocaleString()}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["回复 ",Se.total_replies.toLocaleString()," 条"]})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"成本效率"}),e.jsx(ub,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-xl font-bold",children:Se.total_messages>0?`¥${(Se.total_cost/Se.total_messages*100).toFixed(2)}`:"¥0.00"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"每100条消息"})]})]})]}),e.jsxs(La,{defaultValue:"trends",className:"space-y-4",children:[e.jsxs(wa,{className:"grid w-full grid-cols-2 sm:grid-cols-4",children:[e.jsx(fs,{value:"trends",children:"趋势"}),e.jsx(fs,{value:"models",children:"模型"}),e.jsx(fs,{value:"activity",children:"活动"}),e.jsx(fs,{value:"daily",children:"日统计"})]}),e.jsxs(Ms,{value:"trends",className:"space-y-4",children:[e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"请求趋势"}),e.jsxs(ct,{children:["最近",f,"小时的请求量变化"]})]}),e.jsx(Ts,{children:e.jsx(si,{config:X,className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(HN,{data:ne,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:k=>ye(k),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:k=>ye(k)})}),e.jsx(qN,{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(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"花费趋势"}),e.jsx(ct,{children:"API调用成本变化"})]}),e.jsx(Ts,{children:e.jsx(si,{config:X,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(bu,{data:ne,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:k=>ye(k),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:k=>ye(k)})}),e.jsx(Gc,{dataKey:"cost",fill:"var(--color-cost)"})]})})})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"Token消耗"}),e.jsx(ct,{children:"Token使用量变化"})]}),e.jsx(Ts,{children:e.jsx(si,{config:X,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(bu,{data:ne,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:k=>ye(k),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:k=>ye(k)})}),e.jsx(Gc,{dataKey:"tokens",fill:"var(--color-tokens)"})]})})})]})]})]}),e.jsx(Ms,{value:"models",className:"space-y-4",children:e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:[e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"模型请求分布"}),e.jsxs(ct,{children:["各模型使用占比 (共 ",D.length," 个模型)"]})]}),e.jsx(Ts,{children:e.jsx(si,{config:Object.fromEntries(D.map((k,se)=>[k.model_name,{label:k.model_name,color:be[se]}])),className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(GN,{children:[e.jsx(ir,{content:e.jsx(ti,{})}),e.jsx(VN,{data:z,cx:"50%",cy:"50%",labelLine:!1,label:({name:k,percent:se})=>se&&se<.05?"":`${k} ${se?(se*100).toFixed(0):0}%`,outerRadius:100,dataKey:"value",children:z.map((k,se)=>e.jsx(FN,{fill:k.fill},`cell-${se}`))})]})})})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"模型详细统计"}),e.jsx(ct,{children:"请求数、花费和性能"})]}),e.jsx(Ts,{children:e.jsx(ss,{className:"h-[300px] sm:h-[400px]",children:e.jsx("div",{className:"space-y-3",children:D.map((k,se)=>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:k.model_name}),e.jsx("div",{className:"w-3 h-3 rounded-full ml-2 flex-shrink-0",style:{backgroundColor:`hsl(var(--chart-${se%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:k.request_count.toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1 font-medium",children:["¥",k.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:[(k.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:[k.avg_response_time.toFixed(2),"s"]})]})]})]},se))})})})]})]})}),e.jsx(Ms,{value:"activity",children:e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"最近活动"}),e.jsx(ct,{children:"最新的API调用记录"})]}),e.jsx(Ts,{children:e.jsx(ss,{className:"h-[400px] sm:h-[500px]",children:e.jsx("div",{className:"space-y-2",children:_e.map((k,se)=>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:k.model}),e.jsx("div",{className:"text-xs text-muted-foreground",children:k.request_type})]}),e.jsx("div",{className:"text-xs text-muted-foreground flex-shrink-0",children:ye(k.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:k.tokens})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1",children:["¥",k.cost.toFixed(4)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"耗时:"}),e.jsxs("span",{className:"ml-1",children:[k.time_cost.toFixed(2),"s"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"状态:"}),e.jsx("span",{className:`ml-1 ${k.status==="success"?"text-green-600":"text-red-600"}`,children:k.status})]})]})]},se))})})})]})}),e.jsx(Ms,{value:"daily",children:e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"每日统计"}),e.jsx(ct,{children:"最近7天的数据汇总"})]}),e.jsx(Ts,{children:e.jsx(si,{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(bu,{data:xe,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:k=>{const se=new Date(k);return`${se.getMonth()+1}/${se.getDate()}`},stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{yAxisId:"left",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{yAxisId:"right",orientation:"right",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:k=>new Date(k).toLocaleDateString("zh-CN")})}),e.jsx(ky,{content:e.jsx(Ng,{})}),e.jsx(Gc,{yAxisId:"left",dataKey:"requests",fill:"var(--color-requests)"}),e.jsx(Gc,{yAxisId:"right",dataKey:"cost",fill:"var(--color-cost)"})]})})})]})})]})]})})}const Ly={theme:"system",setTheme:()=>null},bg=u.createContext(Ly),$u=()=>{const n=u.useContext(bg);if(n===void 0)throw new Error("useTheme must be used within a ThemeProvider");return n},Uy=(n,i,c)=>{const d=document.documentElement.classList.contains("no-animations");if(!document.startViewTransition||d){i(n);return}const h=c.clientX,x=c.clientY,f=Math.hypot(Math.max(h,innerWidth-h),Math.max(x,innerHeight-x));document.startViewTransition(()=>{i(n)}).ready.then(()=>{document.documentElement.animate({clipPath:[`circle(0px at ${h}px ${x}px)`,`circle(${f}px at ${h}px ${x}px)`]},{duration:500,easing:"ease-in-out",pseudoElement:"::view-transition-new(root)"})})},yg=u.createContext(void 0),wg=()=>{const n=u.useContext(yg);if(n===void 0)throw new Error("useAnimation must be used within an AnimationProvider");return n},Xe=u.forwardRef(({className:n,...i},c)=>e.jsx(Cp,{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),...i,ref:c,children:e.jsx(wN,{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")})}));Xe.displayName=Cp.displayName;const By=ci("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"),b=u.forwardRef(({className:n,...i},c)=>e.jsx(Hp,{ref:c,className:$(By(),n),...i}));b.displayName=Hp.displayName;const oe=u.forwardRef(({className:n,type:i,...c},d)=>e.jsx("input",{type:i,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,...c}));oe.displayName="Input";const Hy=[{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 qy(n){const i=Hy.map(d=>({id:d.id,label:d.label,description:d.description,passed:d.validate(n)}));return{isValid:i.every(d=>d.passed),rules:i}}const Qu="0.11.6",Yu="MaiBot Dashboard",Gy=`${Yu} v${Qu}`,Vy=(n="v")=>`${n}${Qu}`,Ft={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"},Aa={theme:"system",accentColor:"blue",enableAnimations:!0,enableWavesBackground:!0,logCacheSize:1e3,logAutoScroll:!0,logFontSize:"xs",logLineSpacing:4,dataSyncInterval:30,wsReconnectInterval:3e3,wsMaxReconnectAttempts:10};function st(n){const i=_g(n),c=localStorage.getItem(i);if(c===null)return Aa[n];const d=Aa[n];if(typeof d=="boolean")return c==="true";if(typeof d=="number"){const h=parseFloat(c);return isNaN(h)?d:h}return c}function ai(n,i){const c=_g(n);localStorage.setItem(c,String(i)),window.dispatchEvent(new CustomEvent("maibot-settings-change",{detail:{key:n,value:i}}))}function Fy(){return{theme:st("theme"),accentColor:st("accentColor"),enableAnimations:st("enableAnimations"),enableWavesBackground:st("enableWavesBackground"),logCacheSize:st("logCacheSize"),logAutoScroll:st("logAutoScroll"),logFontSize:st("logFontSize"),logLineSpacing:st("logLineSpacing"),dataSyncInterval:st("dataSyncInterval"),wsReconnectInterval:st("wsReconnectInterval"),wsMaxReconnectAttempts:st("wsMaxReconnectAttempts")}}function $y(){const n=Fy(),i=localStorage.getItem(Ft.COMPLETED_TOURS),c=i?JSON.parse(i):[];return{...n,completedTours:c}}function Qy(n){const i=[],c=[];for(const[d,h]of Object.entries(n)){if(d==="completedTours"){Array.isArray(h)?(localStorage.setItem(Ft.COMPLETED_TOURS,JSON.stringify(h)),i.push("completedTours")):c.push("completedTours");continue}if(d in Aa){const x=d,f=Aa[x];if(typeof h==typeof f){if(x==="theme"&&!["light","dark","system"].includes(h)){c.push(d);continue}if(x==="logFontSize"&&!["xs","sm","base"].includes(h)){c.push(d);continue}ai(x,h),i.push(d)}else c.push(d)}else c.push(d)}return{success:i.length>0,imported:i,skipped:c}}function Yy(){for(const n of Object.keys(Aa))ai(n,Aa[n]);localStorage.removeItem(Ft.COMPLETED_TOURS),window.dispatchEvent(new CustomEvent("maibot-settings-reset"))}function Xy(){const n=[],i=[],c=[];for(let d=0;dd.size-c.size),{used:n,items:localStorage.length,details:i}}function Ky(n){if(n===0)return"0 B";const i=1024,c=["B","KB","MB"],d=Math.floor(Math.log(n)/Math.log(i));return parseFloat((n/Math.pow(i,d)).toFixed(2))+" "+c[d]}function _g(n){return{theme:Ft.THEME,accentColor:Ft.ACCENT_COLOR,enableAnimations:Ft.ENABLE_ANIMATIONS,enableWavesBackground:Ft.ENABLE_WAVES_BACKGROUND,logCacheSize:Ft.LOG_CACHE_SIZE,logAutoScroll:Ft.LOG_AUTO_SCROLL,logFontSize:Ft.LOG_FONT_SIZE,logLineSpacing:Ft.LOG_LINE_SPACING,dataSyncInterval:Ft.DATA_SYNC_INTERVAL,wsReconnectInterval:Ft.WS_RECONNECT_INTERVAL,wsMaxReconnectAttempts:Ft.WS_MAX_RECONNECT_ATTEMPTS}[n]}const Ma=u.forwardRef(({className:n,...i},c)=>e.jsxs(kp,{ref:c,className:$("relative flex w-full touch-none select-none items-center",n),...i,children:[e.jsx(_N,{className:"relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20",children:e.jsx(SN,{className:"absolute h-full bg-primary"})}),e.jsx(CN,{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=kp.displayName;class Jy{ws=null;reconnectTimeout=null;reconnectAttempts=0;heartbeatInterval=null;logCallbacks=new Set;connectionCallbacks=new Set;isConnected=!1;logCache=[];getMaxCacheSize(){return st("logCacheSize")}getMaxReconnectAttempts(){return st("wsMaxReconnectAttempts")}getReconnectInterval(){return st("wsReconnectInterval")}getWebSocketUrl(){{const i=window.location.protocol==="https:"?"wss:":"ws:",c=window.location.host;return`${i}//${c}/ws/logs`}}connect(){if(this.ws?.readyState===WebSocket.OPEN||this.ws?.readyState===WebSocket.CONNECTING)return;const i=this.getWebSocketUrl();try{this.ws=new WebSocket(i),this.ws.onopen=()=>{this.isConnected=!0,this.reconnectAttempts=0,this.notifyConnection(!0),this.startHeartbeat()},this.ws.onmessage=c=>{try{if(c.data==="pong")return;const d=JSON.parse(c.data);this.notifyLog(d)}catch(d){console.error("解析日志消息失败:",d)}},this.ws.onerror=c=>{console.error("❌ WebSocket 错误:",c),this.isConnected=!1,this.notifyConnection(!1)},this.ws.onclose=()=>{this.isConnected=!1,this.notifyConnection(!1),this.stopHeartbeat(),this.attemptReconnect()}}catch(c){console.error("创建 WebSocket 连接失败:",c),this.attemptReconnect()}}attemptReconnect(){const i=this.getMaxReconnectAttempts();if(this.reconnectAttempts>=i)return;this.reconnectAttempts+=1;const c=this.getReconnectInterval(),d=Math.min(c*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(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(d=>d.id===i.id)){this.logCache.push(i);const d=this.getMaxCacheSize();this.logCache.length>d&&(this.logCache=this.logCache.slice(-d)),this.logCallbacks.forEach(h=>{try{h(i)}catch(x){console.error("日志回调执行失败:",x)}})}}notifyConnection(i){this.connectionCallbacks.forEach(c=>{try{c(i)}catch(d){console.error("连接状态回调执行失败:",d)}})}getAllLogs(){return[...this.logCache]}clearLogs(){this.logCache=[]}getConnectionStatus(){return this.isConnected}}const rn=new Jy;typeof window<"u"&&rn.connect();const $s=XN,Xu=KN,Zy=QN,Sg=u.forwardRef(({className:n,...i},c)=>e.jsx(qp,{ref:c,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),...i}));Sg.displayName=qp.displayName;const Bs=u.forwardRef(({className:n,children:i,preventOutsideClose:c=!1,...d},h)=>e.jsxs(Zy,{children:[e.jsx(Sg,{}),e.jsxs(Gp,{ref:h,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:c?x=>x.preventDefault():void 0,onInteractOutside:c?x=>x.preventDefault():void 0,...d,children:[i,e.jsxs(YN,{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(dl,{className:"h-4 w-4"}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Bs.displayName=Gp.displayName;const Hs=({className:n,...i})=>e.jsx("div",{className:$("flex flex-col space-y-1.5 text-center sm:text-left",n),...i});Hs.displayName="DialogHeader";const at=({className:n,...i})=>e.jsx("div",{className:$("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",n),...i});at.displayName="DialogFooter";const qs=u.forwardRef(({className:n,...i},c)=>e.jsx(Vp,{ref:c,className:$("text-lg font-semibold leading-none tracking-tight",n),...i}));qs.displayName=Vp.displayName;const Is=u.forwardRef(({className:n,...i},c)=>e.jsx(Fp,{ref:c,className:$("text-sm text-muted-foreground",n),...i}));Is.displayName=Fp.displayName;const ps=TN,tt=EN,Iy=kN,Cg=u.forwardRef(({className:n,...i},c)=>e.jsx(Tp,{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),...i,ref:c}));Cg.displayName=Tp.displayName;const is=u.forwardRef(({className:n,...i},c)=>e.jsxs(Iy,{children:[e.jsx(Cg,{}),e.jsx(Ep,{ref:c,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),...i})]}));is.displayName=Ep.displayName;const rs=({className:n,...i})=>e.jsx("div",{className:$("flex flex-col space-y-2 text-center sm:text-left",n),...i});rs.displayName="AlertDialogHeader";const cs=({className:n,...i})=>e.jsx("div",{className:$("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",n),...i});cs.displayName="AlertDialogFooter";const os=u.forwardRef(({className:n,...i},c)=>e.jsx(zp,{ref:c,className:$("text-lg font-semibold",n),...i}));os.displayName=zp.displayName;const ds=u.forwardRef(({className:n,...i},c)=>e.jsx(Ap,{ref:c,className:$("text-sm text-muted-foreground",n),...i}));ds.displayName=Ap.displayName;const us=u.forwardRef(({className:n,...i},c)=>e.jsx(Mp,{ref:c,className:$(gr(),n),...i}));us.displayName=Mp.displayName;const ms=u.forwardRef(({className:n,...i},c)=>e.jsx(Dp,{ref:c,className:$(gr({variant:"outline"}),"mt-2 sm:mt-0",n),...i}));ms.displayName=Dp.displayName;function Py(){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(La,{defaultValue:"appearance",className:"w-full",children:[e.jsxs(wa,{className:"grid w-full grid-cols-2 sm:grid-cols-4 gap-0.5 sm:gap-1 h-auto p-1",children:[e.jsxs(fs,{value:"appearance",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(mb,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"外观"})]}),e.jsxs(fs,{value:"security",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(hb,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"安全"})]}),e.jsxs(fs,{value:"other",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(oi,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"其他"})]}),e.jsxs(fs,{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(ss,{className:"h-[calc(100vh-240px)] sm:h-[calc(100vh-280px)] mt-4 sm:mt-6",children:[e.jsx(Ms,{value:"appearance",className:"mt-0",children:e.jsx(Wy,{})}),e.jsx(Ms,{value:"security",className:"mt-0",children:e.jsx(e0,{})}),e.jsx(Ms,{value:"other",className:"mt-0",children:e.jsx(s0,{})}),e.jsx(Ms,{value:"about",className:"mt-0",children:e.jsx(t0,{})})]})]})]})}function tp(n){const i=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)i.style.setProperty("--primary",d.hsl),d.gradient?(i.style.setProperty("--primary-gradient",d.gradient),i.classList.add("has-gradient")):(i.style.removeProperty("--primary-gradient"),i.classList.remove("has-gradient"));else if(n.startsWith("#")){const h=x=>{x=x.replace("#","");const f=parseInt(x.substring(0,2),16)/255,j=parseInt(x.substring(2,4),16)/255,p=parseInt(x.substring(4,6),16)/255,w=Math.max(f,j,p),v=Math.min(f,j,p);let y=0,S=0;const C=(w+v)/2;if(w!==v){const M=w-v;switch(S=C>.5?M/(2-w-v):M/(w+v),w){case f:y=((j-p)/M+(jlocalStorage.getItem("accent-color")||"blue");u.useEffect(()=>{const w=localStorage.getItem("accent-color")||"blue";tp(w)},[]);const p=w=>{j(w),localStorage.setItem("accent-color",w),tp(w)};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(Eu,{value:"light",current:n,onChange:i,label:"浅色",description:"始终使用浅色主题"}),e.jsx(Eu,{value:"dark",current:n,onChange:i,label:"深色",description:"始终使用深色主题"}),e.jsx(Eu,{value:"system",current:n,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(xa,{value:"blue",current:f,onChange:p,label:"蓝色",colorClass:"bg-blue-500"}),e.jsx(xa,{value:"purple",current:f,onChange:p,label:"紫色",colorClass:"bg-purple-500"}),e.jsx(xa,{value:"green",current:f,onChange:p,label:"绿色",colorClass:"bg-green-500"}),e.jsx(xa,{value:"orange",current:f,onChange:p,label:"橙色",colorClass:"bg-orange-500"}),e.jsx(xa,{value:"pink",current:f,onChange:p,label:"粉色",colorClass:"bg-pink-500"}),e.jsx(xa,{value:"red",current:f,onChange:p,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(xa,{value:"gradient-sunset",current:f,onChange:p,label:"日落",colorClass:"bg-gradient-to-r from-orange-500 to-pink-500"}),e.jsx(xa,{value:"gradient-ocean",current:f,onChange:p,label:"海洋",colorClass:"bg-gradient-to-r from-blue-500 to-cyan-500"}),e.jsx(xa,{value:"gradient-forest",current:f,onChange:p,label:"森林",colorClass:"bg-gradient-to-r from-green-500 to-emerald-500"}),e.jsx(xa,{value:"gradient-aurora",current:f,onChange:p,label:"极光",colorClass:"bg-gradient-to-r from-purple-500 to-pink-500"}),e.jsx(xa,{value:"gradient-fire",current:f,onChange:p,label:"烈焰",colorClass:"bg-gradient-to-r from-red-500 to-orange-500"}),e.jsx(xa,{value:"gradient-twilight",current:f,onChange:p,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:w=>p(w.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(oe,{type:"text",value:f,onChange:w=>p(w.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(b,{htmlFor:"animations",className:"text-base font-medium cursor-pointer",children:"启用动画效果"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后将禁用所有过渡动画和特效,提升性能"})]}),e.jsx(Xe,{id:"animations",checked:c,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(b,{htmlFor:"waves-background",className:"text-base font-medium cursor-pointer",children:"登录页波浪背景"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后登录页将使用纯色背景,适合低性能设备"})]}),e.jsx(Xe,{id:"waves-background",checked:h,onCheckedChange:x})]})})]})]})]})}function e0(){const n=ga(),[i,c]=u.useState(""),[d,h]=u.useState(""),[x,f]=u.useState(!1),[j,p]=u.useState(!1),[w,v]=u.useState(!1),[y,S]=u.useState(!1),[C,M]=u.useState(!1),[F,U]=u.useState(!1),[O,K]=u.useState(""),[H,A]=u.useState(!1),{toast:V}=Gs(),Q=u.useMemo(()=>qy(d),[d]),T=async ge=>{if(!i){V({title:"无法复制",description:"Token 存储在安全 Cookie 中,请重新生成以获取新 Token",variant:"destructive"});return}try{await navigator.clipboard.writeText(ge),M(!0),V({title:"复制成功",description:"Token 已复制到剪贴板"}),setTimeout(()=>M(!1),2e3)}catch{V({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},D=async()=>{if(!d.trim()){V({title:"输入错误",description:"请输入新的 Token",variant:"destructive"});return}if(!Q.isValid){const ge=Q.rules.filter(ye=>!ye.passed).map(ye=>ye.label).join(", ");V({title:"格式错误",description:`Token 不符合要求: ${ge}`,variant:"destructive"});return}v(!0);try{const ge=await fetch("/api/webui/auth/update",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({new_token:d.trim()})}),ye=await ge.json();ge.ok&&ye.success?(h(""),c(d.trim()),V({title:"更新成功",description:"Access Token 已更新,即将跳转到登录页"}),setTimeout(()=>{n({to:"/auth"})},1500)):V({title:"更新失败",description:ye.message||"无法更新 Token",variant:"destructive"})}catch(ge){console.error("更新 Token 错误:",ge),V({title:"更新失败",description:"连接服务器失败",variant:"destructive"})}finally{v(!1)}},ne=async()=>{S(!0);try{const ge=await fetch("/api/webui/auth/regenerate",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include"}),ye=await ge.json();ge.ok&&ye.success?(c(ye.token),K(ye.token),U(!0),A(!1),V({title:"生成成功",description:"新的 Access Token 已生成,请及时保存"})):V({title:"生成失败",description:ye.message||"无法生成新 Token",variant:"destructive"})}catch(ge){console.error("生成 Token 错误:",ge),V({title:"生成失败",description:"连接服务器失败",variant:"destructive"})}finally{S(!1)}},xe=async()=>{try{await navigator.clipboard.writeText(O),A(!0),V({title:"复制成功",description:"Token 已复制到剪贴板"})}catch{V({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},_e=()=>{U(!1),setTimeout(()=>{K(""),A(!1)},300),setTimeout(()=>{n({to:"/auth"})},500)},Se=ge=>{ge||_e()};return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsx($s,{open:F,onOpenChange:Se,children:e.jsxs(Bs,{className:"sm:max-w-md",children:[e.jsxs(Hs,{children:[e.jsxs(qs,{className:"flex items-center gap-2",children:[e.jsx(ya,{className:"h-5 w-5 text-yellow-500"}),"新的 Access Token"]}),e.jsx(Is,{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(b,{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:O})]}),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(ya,{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(N,{variant:"outline",onClick:xe,className:"gap-2",children:H?e.jsxs(e.Fragment,{children:[e.jsx(sa,{className:"h-4 w-4 text-green-500"}),"已复制"]}):e.jsxs(e.Fragment,{children:[e.jsx(Pc,{className:"h-4 w-4"}),"复制 Token"]})}),e.jsx(N,{onClick:_e,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(b,{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(oe,{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?f(!x):V({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(xr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Dt,{className:"h-4 w-4 text-muted-foreground"})})]}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[e.jsx(N,{variant:"outline",size:"icon",onClick:()=>T(i),title:"复制到剪贴板",className:"flex-shrink-0",disabled:!i,children:C?e.jsx(sa,{className:"h-4 w-4 text-green-500"}):e.jsx(Pc,{className:"h-4 w-4"})}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",disabled:y,className:"gap-2 flex-1 sm:flex-none",children:[e.jsx(Ct,{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(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认重新生成 Token"}),e.jsx(ds,{children:"这将生成一个新的 64 位安全令牌,并使当前 Token 立即失效。 您需要使用新 Token 重新登录系统。此操作不可撤销,确定要继续吗?"})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:ne,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(b,{htmlFor:"new-token",className:"text-sm",children:"新的访问令牌"}),e.jsxs("div",{className:"relative",children:[e.jsx(oe,{id:"new-token",type:j?"text":"password",value:d,onChange:ge=>h(ge.target.value),className:"pr-10 font-mono text-sm",placeholder:"输入自定义 Token"}),e.jsx("button",{onClick:()=>p(!j),className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:j?"隐藏":"显示",children:j?e.jsx(xr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Dt,{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:Q.rules.map(ge=>e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[ge.passed?e.jsx(fa,{className:"h-4 w-4 text-green-500 flex-shrink-0"}):e.jsx(ng,{className:"h-4 w-4 text-muted-foreground flex-shrink-0"}),e.jsx("span",{className:$(ge.passed?"text-green-600 dark:text-green-400":"text-muted-foreground"),children:ge.label})]},ge.id))}),Q.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(sa,{className:"h-4 w-4"}),e.jsx("span",{className:"font-medium",children:"Token 格式正确,可以使用"})]})})]})]}),e.jsx(N,{onClick:D,disabled:w||!Q.isValid||!d,className:"w-full sm:w-auto",children:w?"更新中...":"更新自定义 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 s0(){const n=ga(),{toast:i}=Gs(),[c,d]=u.useState(!1),[h,x]=u.useState(!1),[f,j]=u.useState(()=>st("logCacheSize")),[p,w]=u.useState(()=>st("wsReconnectInterval")),[v,y]=u.useState(()=>st("wsMaxReconnectAttempts")),[S,C]=u.useState(()=>st("dataSyncInterval")),[M,F]=u.useState(()=>sp()),[U,O]=u.useState(!1),[K,H]=u.useState(!1),A=u.useRef(null);if(h)throw new Error("这是一个手动触发的测试错误,用于验证错误边界组件是否正常工作。");const V=()=>{F(sp())},Q=z=>{const X=z[0];j(X),ai("logCacheSize",X)},T=z=>{const X=z[0];w(X),ai("wsReconnectInterval",X)},D=z=>{const X=z[0];y(X),ai("wsMaxReconnectAttempts",X)},ne=z=>{const X=z[0];C(X),ai("dataSyncInterval",X)},xe=()=>{rn.clearLogs(),i({title:"日志已清除",description:"日志缓存已清空"})},_e=()=>{const z=Xy();V(),i({title:"缓存已清除",description:`已清除 ${z.clearedKeys.length} 项缓存数据`})},Se=()=>{O(!0);try{const z=$y(),X=JSON.stringify(z,null,2),k=new Blob([X],{type:"application/json"}),se=URL.createObjectURL(k),_=document.createElement("a");_.href=se,_.download=`maibot-webui-settings-${new Date().toISOString().slice(0,10)}.json`,document.body.appendChild(_),_.click(),document.body.removeChild(_),URL.revokeObjectURL(se),i({title:"导出成功",description:"设置已导出为 JSON 文件"})}catch(z){console.error("导出设置失败:",z),i({title:"导出失败",description:"无法导出设置",variant:"destructive"})}finally{O(!1)}},ge=z=>{const X=z.target.files?.[0];if(!X)return;H(!0);const k=new FileReader;k.onload=se=>{try{const _=se.target?.result,ue=JSON.parse(_),ie=Qy(ue);ie.success?(j(st("logCacheSize")),w(st("wsReconnectInterval")),y(st("wsMaxReconnectAttempts")),C(st("dataSyncInterval")),V(),i({title:"导入成功",description:`成功导入 ${ie.imported.length} 项设置${ie.skipped.length>0?`,跳过 ${ie.skipped.length} 项`:""}`}),(ie.imported.includes("theme")||ie.imported.includes("accentColor"))&&i({title:"提示",description:"部分设置需要刷新页面才能完全生效"})):i({title:"导入失败",description:"没有有效的设置项可导入",variant:"destructive"})}catch(_){console.error("导入设置失败:",_),i({title:"导入失败",description:"文件格式无效",variant:"destructive"})}finally{H(!1),A.current&&(A.current.value="")}},k.readAsText(X)},ye=()=>{Yy(),j(Aa.logCacheSize),w(Aa.wsReconnectInterval),y(Aa.wsMaxReconnectAttempts),C(Aa.dataSyncInterval),V(),i({title:"已重置",description:"所有设置已恢复为默认值,刷新页面以应用更改"})},be=async()=>{d(!0);try{const z=localStorage.getItem("access-token"),X=await fetch("/api/webui/setup/reset",{method:"POST",headers:{Authorization:`Bearer ${z}`}}),k=await X.json();X.ok&&k.success?(i({title:"重置成功",description:"即将进入初次配置向导"}),setTimeout(()=>{n({to:"/setup"})},1e3)):i({title:"重置失败",description:k.message||"无法重置配置状态",variant:"destructive"})}catch(z){console.error("重置配置状态错误:",z),i({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(Ic,{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(xb,{className:"h-4 w-4"}),"本地存储使用"]}),e.jsx(N,{variant:"ghost",size:"sm",onClick:V,className:"h-7 px-2",children:e.jsx(Ct,{className:"h-3 w-3"})})]}),e.jsx("div",{className:"text-2xl font-bold text-primary",children:Ky(M.used)}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:[M.items," 个存储项"]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{className:"text-sm font-medium",children:"日志缓存大小"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[f," 条"]})]}),e.jsx(Ma,{value:[f],onValueChange:Q,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(b,{className:"text-sm font-medium",children:"首页数据刷新间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[S," 秒"]})]}),e.jsx(Ma,{value:[S],onValueChange:ne,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(b,{className:"text-sm font-medium",children:"WebSocket 重连间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[p/1e3," 秒"]})]}),e.jsx(Ma,{value:[p],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(b,{className:"text-sm font-medium",children:"WebSocket 最大重连次数"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[v," 次"]})]}),e.jsx(Ma,{value:[v],onValueChange:D,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(N,{variant:"outline",size:"sm",onClick:xe,className:"gap-2",children:[e.jsx(ls,{className:"h-4 w-4"}),"清除日志缓存"]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:"gap-2",children:[e.jsx(ls,{className:"h-4 w-4"}),"清除本地缓存"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认清除本地缓存"}),e.jsx(ds,{children:"这将清除所有本地缓存的设置和数据(不包括登录凭证)。 您可能需要重新配置部分偏好设置。确定要继续吗?"})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:_e,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(rl,{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(N,{variant:"outline",onClick:Se,disabled:U,className:"gap-2",children:[e.jsx(rl,{className:"h-4 w-4"}),U?"导出中...":"导出设置"]}),e.jsx("input",{ref:A,type:"file",accept:".json",onChange:ge,className:"hidden"}),e.jsxs(N,{variant:"outline",onClick:()=>A.current?.click(),disabled:K,className:"gap-2",children:[e.jsx(fr,{className:"h-4 w-4"}),K?"导入中...":"导入设置"]})]}),e.jsx("div",{className:"pt-2 border-t",children:e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:"gap-2 text-destructive hover:text-destructive",children:[e.jsx(Zc,{className:"h-4 w-4"}),"重置所有设置为默认值"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认重置所有设置"}),e.jsx(ds,{children:"这将把所有界面设置恢复为默认值,包括主题、颜色、动画等偏好设置。 此操作不会影响您的登录状态。确定要继续吗?"})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:ye,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(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",disabled:c,className:"gap-2",children:[e.jsx(Zc,{className:$("h-4 w-4",c&&"animate-spin")}),"重新进行初次配置"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认重新配置"}),e.jsx(ds,{children:"这将带您重新进入初次配置向导。您可以重新设置系统的基础配置项。确定要继续吗?"})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{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(ya,{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(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"destructive",className:"gap-2",children:[e.jsx(ya,{className:"h-4 w-4"}),"触发测试错误"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认触发错误"}),e.jsx(ds,{children:"这将手动触发一个 React 错误,用于测试错误边界组件的显示效果。 页面将显示错误界面,您可以通过刷新页面或点击返回首页来恢复。"})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>x(!0),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认触发"})]})]})]})]})]})]})}function t0(){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:["关于 ",Yu]}),e.jsxs("div",{className:"space-y-2 text-xs sm:text-sm text-muted-foreground",children:[e.jsxs("p",{children:["版本: ",Qu]}),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(ss,{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(Zs,{name:"React",description:"用户界面构建库",license:"MIT"}),e.jsx(Zs,{name:"shadcn/ui",description:"优雅的 React 组件库",license:"MIT"}),e.jsx(Zs,{name:"Radix UI",description:"无样式的可访问组件库",license:"MIT"}),e.jsx(Zs,{name:"Tailwind CSS",description:"实用优先的 CSS 框架",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"TanStack Router",description:"类型安全的路由库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"React Hook Form",description:"高性能表单库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"clsx",description:"条件 className 构建工具",license:"MIT"}),e.jsx(Zs,{name:"tailwind-merge",description:"Tailwind 类名合并工具",license:"MIT"}),e.jsx(Zs,{name:"class-variance-authority",description:"组件变体管理",license:"Apache-2.0"}),e.jsx(Zs,{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(Zs,{name:"Framer Motion",description:"React 动画库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"FastAPI",description:"现代化 Python Web 框架",license:"MIT"}),e.jsx(Zs,{name:"Uvicorn",description:"ASGI 服务器",license:"BSD-3-Clause"}),e.jsx(Zs,{name:"Pydantic",description:"数据验证库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"TypeScript",description:"JavaScript 的超集",license:"Apache-2.0"}),e.jsx(Zs,{name:"Vite",description:"下一代前端构建工具",license:"MIT"}),e.jsx(Zs,{name:"ESLint",description:"JavaScript 代码检查工具",license:"MIT"}),e.jsx(Zs,{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 Zs({name:n,description:i,license:c}){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: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:c})]})}function Eu({value:n,current:i,onChange:c,label:d,description:h}){const x=i===n;return e.jsxs("button",{onClick:()=>c(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:h})]}),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 xa({value:n,current:i,onChange:c,label:d,colorClass:h}){const x=i===n;return e.jsxs("button",{onClick:()=>c(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",h)}),e.jsx("div",{className:"text-[10px] sm:text-xs font-medium text-center",children:d})]})]})}class a0{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 c=0;c<256;c++)this.p[c]=Math.floor(Math.random()*256);this.perm=[];for(let c=0;c<512;c++)this.perm[c]=this.p[c&255]}dot(i,c,d){return i[0]*c+i[1]*d}mix(i,c,d){return(1-d)*i+d*c}fade(i){return i*i*i*(i*(i*6-15)+10)}perlin2(i,c){const d=Math.floor(i)&255,h=Math.floor(c)&255;i-=Math.floor(i),c-=Math.floor(c);const x=this.fade(i),f=this.fade(c),j=this.perm[d]+h,p=this.perm[j],w=this.perm[j+1],v=this.perm[d+1]+h,y=this.perm[v],S=this.perm[v+1];return this.mix(this.mix(this.dot(this.grad3[p%12],i,c),this.dot(this.grad3[y%12],i-1,c),x),this.mix(this.dot(this.grad3[w%12],i,c-1),this.dot(this.grad3[S%12],i-1,c-1),x),f)}}function ap(){const n=u.useRef(null),i=u.useRef(null),c=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 a0(Math.random()),bounding:null});return u.useEffect(()=>{const h=i.current,x=n.current;if(!h||!x)return;const f=d.current,j=()=>{const F=h.getBoundingClientRect();f.bounding=F,x.style.width=`${F.width}px`,x.style.height=`${F.height}px`},p=()=>{if(!f.bounding)return;const{width:F,height:U}=f.bounding;f.lines=[],f.paths.forEach(ne=>ne.remove()),f.paths=[];const O=10,K=32,H=F+200,A=U+30,V=Math.ceil(H/O),Q=Math.ceil(A/K),T=(F-O*V)/2,D=(U-K*Q)/2;for(let ne=0;ne<=V;ne++){const xe=[];for(let Se=0;Se<=Q;Se++){const ge={x:T+O*ne,y:D+K*Se,wave:{x:0,y:0},cursor:{x:0,y:0,vx:0,vy:0}};xe.push(ge)}const _e=document.createElementNS("http://www.w3.org/2000/svg","path");x.appendChild(_e),f.paths.push(_e),f.lines.push(xe)}},w=F=>{const{lines:U,mouse:O,noise:K}=f;U.forEach(H=>{H.forEach(A=>{const V=K.perlin2((A.x+F*.0125)*.002,(A.y+F*.005)*.0015)*12;A.wave.x=Math.cos(V)*32,A.wave.y=Math.sin(V)*16;const Q=A.x-O.sx,T=A.y-O.sy,D=Math.hypot(Q,T),ne=Math.max(175,O.vs);if(D{const O={x:F.x+F.wave.x+(U?F.cursor.x:0),y:F.y+F.wave.y+(U?F.cursor.y:0)};return O.x=Math.round(O.x*10)/10,O.y=Math.round(O.y*10)/10,O},y=()=>{const{lines:F,paths:U}=f;F.forEach((O,K)=>{let H=v(O[0],!1),A=`M ${H.x} ${H.y}`;O.forEach((V,Q)=>{const T=Q===O.length-1;H=v(V,!T),A+=`L ${H.x} ${H.y}`}),U[K].setAttribute("d",A)})},S=F=>{const{mouse:U}=f;U.sx+=(U.x-U.sx)*.1,U.sy+=(U.y-U.sy)*.1;const O=U.x-U.lx,K=U.y-U.ly,H=Math.hypot(O,K);U.v=H,U.vs+=(H-U.vs)*.1,U.vs=Math.min(100,U.vs),U.lx=U.x,U.ly=U.y,U.a=Math.atan2(K,O),h&&(h.style.setProperty("--x",`${U.sx}px`),h.style.setProperty("--y",`${U.sy}px`)),w(F),y(),c.current=requestAnimationFrame(S)},C=F=>{if(!f.bounding)return;const{mouse:U}=f;U.x=F.pageX-f.bounding.left,U.y=F.pageY-f.bounding.top+window.scrollY,U.set||(U.sx=U.x,U.sy=U.y,U.lx=U.x,U.ly=U.y,U.set=!0)},M=()=>{j(),p()};return j(),p(),window.addEventListener("resize",M),window.addEventListener("mousemove",C),c.current=requestAnimationFrame(S),()=>{window.removeEventListener("resize",M),window.removeEventListener("mousemove",C),c.current&&cancelAnimationFrame(c.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:n,style:{display:"block",width:"100%",height:"100%"},children:e.jsx("style",{children:` +`)}}):null},ir=GN,ti=u.forwardRef(({active:n,payload:i,className:c,indicator:d="dot",hideLabel:h=!1,hideIndicator:f=!1,label:x,labelFormatter:j,labelClassName:p,formatter:w,color:v,nameKey:y,labelKey:S},k)=>{const{config:O}=yg(),Y=u.useMemo(()=>{if(h||!i?.length)return null;const[R]=i,H=`${S||R?.dataKey||R?.name||"value"}`,D=Hu(O,R,H),C=!S&&typeof x=="string"?O[x]?.label||x:D?.label;return j?e.jsx("div",{className:X("font-medium",p),children:j(C,i)}):C?e.jsx("div",{className:X("font-medium",p),children:C}):null},[x,j,i,h,p,O,S]);if(!n||!i?.length)return null;const L=i.length===1&&d!=="dot";return e.jsxs("div",{ref:k,className:X("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",c),children:[L?null:Y,e.jsx("div",{className:"grid gap-1.5",children:i.filter(R=>R.type!=="none").map((R,H)=>{const D=`${y||R.name||R.dataKey||"value"}`,C=Hu(O,R,D),$=v||R.payload.fill||R.color;return e.jsx("div",{className:X("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:w&&R?.value!==void 0&&R.name?w(R.value,R.name,R,H,R.payload):e.jsxs(e.Fragment,{children:[C?.icon?e.jsx(C.icon,{}):!f&&e.jsx("div",{className:X("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":L&&d==="dashed"}),style:{"--color-bg":$,"--color-border":$}}),e.jsxs("div",{className:X("flex flex-1 justify-between leading-none",L?"items-end":"items-center"),children:[e.jsxs("div",{className:"grid gap-1.5",children:[L?Y:null,e.jsx("span",{className:"text-muted-foreground",children:C?.label||R.name})]}),R.value&&e.jsx("span",{className:"font-mono font-medium tabular-nums text-foreground",children:R.value.toLocaleString()})]})]})},R.dataKey)})})]})});ti.displayName="ChartTooltip";const Ay=VN,wg=u.forwardRef(({className:n,hideIcon:i=!1,payload:c,verticalAlign:d="bottom",nameKey:h},f)=>{const{config:x}=yg();return c?.length?e.jsx("div",{ref:f,className:X("flex items-center justify-center gap-4",d==="top"?"pb-3":"pt-3",n),children:c.filter(j=>j.type!=="none").map(j=>{const p=`${h||j.dataKey||"value"}`,w=Hu(x,j,p);return e.jsxs("div",{className:X("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"),children:[w?.icon&&!i?e.jsx(w.icon,{}):e.jsx("div",{className:"h-2 w-2 shrink-0 rounded-[2px]",style:{backgroundColor:j.color}}),w?.label]},j.value)})}):null});wg.displayName="ChartLegend";function Hu(n,i,c){if(typeof i!="object"||i===null)return;const d="payload"in i&&typeof i.payload=="object"&&i.payload!==null?i.payload:void 0;let h=c;return c in i&&typeof i[c]=="string"?h=i[c]:d&&c in d&&typeof d[c]=="string"&&(h=d[c]),h in n?n[h]:n[c]}const gr=ci("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"}}),N=u.forwardRef(({className:n,variant:i,size:c,asChild:d=!1,...h},f)=>{const x=d?KN:"button";return e.jsx(x,{className:X(gr({variant:i,size:c,className:n})),ref:f,...h})});N.displayName="Button";const My=ci("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 $e({className:n,variant:i,...c}){return e.jsx("div",{className:X(My({variant:i}),n),...c})}const Dy=5,Oy=5e3;let ku=0;function Ry(){return ku=(ku+1)%Number.MAX_SAFE_INTEGER,ku.toString()}const Tu=new Map,ap=n=>{if(Tu.has(n))return;const i=setTimeout(()=>{Tu.delete(n),hr({type:"REMOVE_TOAST",toastId:n})},Oy);Tu.set(n,i)},Ly=(n,i)=>{switch(i.type){case"ADD_TOAST":return{...n,toasts:[i.toast,...n.toasts].slice(0,Dy)};case"UPDATE_TOAST":return{...n,toasts:n.toasts.map(c=>c.id===i.toast.id?{...c,...i.toast}:c)};case"DISMISS_TOAST":{const{toastId:c}=i;return c?ap(c):n.toasts.forEach(d=>{ap(d.id)}),{...n,toasts:n.toasts.map(d=>d.id===c||c===void 0?{...d,open:!1}:d)}}case"REMOVE_TOAST":return i.toastId===void 0?{...n,toasts:[]}:{...n,toasts:n.toasts.filter(c=>c.id!==i.toastId)}}},Kc=[];let Jc={toasts:[]};function hr(n){Jc=Ly(Jc,n),Kc.forEach(i=>{i(Jc)})}function Uy({...n}){const i=Ry(),c=h=>hr({type:"UPDATE_TOAST",toast:{...h,id:i}}),d=()=>hr({type:"DISMISS_TOAST",toastId:i});return hr({type:"ADD_TOAST",toast:{...n,id:i,open:!0,onOpenChange:h=>{h||d()}}}),{id:i,dismiss:d,update:c}}function Vs(){const[n,i]=u.useState(Jc);return u.useEffect(()=>(Kc.push(i),()=>{const c=Kc.indexOf(i);c>-1&&Kc.splice(c,1)}),[n]),{...n,toast:Uy,dismiss:c=>hr({type:"DISMISS_TOAST",toastId:c})}}const By=n=>{const i=[];for(let c=0;c{try{k(!0);const E=await Bc.get("https://v1.hitokoto.cn/?c=a&c=b&c=c&c=d&c=h&c=i&c=k");y({hitokoto:E.data.hitokoto,from:E.data.from||E.data.from_who||"未知"})}catch(E){console.error("获取一言失败:",E),y({hitokoto:"人生就像一盒巧克力,你永远不知道下一颗是什么味道。",from:"阿甘正传"})}finally{k(!1)}},[]),C=u.useCallback(async()=>{try{const E=localStorage.getItem("access-token"),se=await Bc.get("/api/webui/system/status",{headers:{Authorization:`Bearer ${E}`}});Y(se.data)}catch(E){console.error("获取机器人状态失败:",E),Y(null)}},[]),$=async()=>{if(!L)try{R(!0);const E=localStorage.getItem("access-token");await Bc.post("/api/webui/system/restart",{},{headers:{Authorization:`Bearer ${E}`}}),H({title:"重启中",description:"麦麦正在重启,请稍候..."}),setTimeout(()=>{C(),R(!1)},3e3)}catch(E){console.error("重启失败:",E),H({title:"重启失败",description:"无法重启麦麦,请检查控制台",variant:"destructive"}),R(!1)}},G=u.useCallback(async()=>{try{const E=localStorage.getItem("access-token"),se=await Bc.get(`/api/webui/statistics/dashboard?hours=${x}`,{headers:{Authorization:`Bearer ${E}`}});i(se.data),d(!1),f(100)}catch(E){console.error("Failed to fetch dashboard data:",E),d(!1),f(100)}},[x]);if(u.useEffect(()=>{if(!c)return;f(0);const E=setTimeout(()=>f(15),200),se=setTimeout(()=>f(30),800),_=setTimeout(()=>f(45),2e3),me=setTimeout(()=>f(60),4e3),re=setTimeout(()=>f(75),6500),le=setTimeout(()=>f(85),9e3),pe=setTimeout(()=>f(92),11e3);return()=>{clearTimeout(E),clearTimeout(se),clearTimeout(_),clearTimeout(me),clearTimeout(re),clearTimeout(le),clearTimeout(pe)}},[c]),u.useEffect(()=>{G(),D(),C()},[G,D,C]),u.useEffect(()=>{if(!p)return;const E=setInterval(()=>{G(),C()},3e4);return()=>clearInterval(E)},[p,G,C]),c||!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(Ct,{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(wr,{value:h,className:"h-2"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[h,"%"]})]})]})});const{summary:T,model_stats:M=[],hourly_data:ne=[],daily_data:fe=[],recent_activity:_e=[]}=n,Se=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},je=E=>{const se=Math.floor(E/3600),_=Math.floor(E%3600/60);return`${se}小时${_}分钟`},ye=E=>new Date(E).toLocaleString("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),be=By(M.length),A=M.map((E,se)=>({name:E.model_name,value:E.request_count,fill:be[se]})),K={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(ss,{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(Ca,{value:x.toString(),onValueChange:E=>j(Number(E)),children:e.jsxs(pa,{className:"grid grid-cols-3 w-full sm:w-auto",children:[e.jsx(ns,{value:"24",children:"24小时"}),e.jsx(ns,{value:"168",children:"7天"}),e.jsx(ns,{value:"720",children:"30天"})]})}),e.jsxs(N,{variant:p?"default":"outline",size:"sm",onClick:()=>w(!p),className:"gap-2",children:[e.jsx(Ct,{className:`h-4 w-4 ${p?"animate-spin":""}`}),e.jsx("span",{className:"hidden sm:inline",children:"自动刷新"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:G,children:e.jsx(Ct,{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:[S?e.jsx(Ng,{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(N,{variant:"ghost",size:"icon",className:"h-7 w-7 shrink-0",onClick:D,disabled:S,children:e.jsx(Ct,{className:`h-3.5 w-3.5 ${S?"animate-spin":""}`})})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-3",children:[e.jsxs(Ze,{className:"lg:col-span-1",children:[e.jsx(ys,{className:"pb-3",children:e.jsxs(ws,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(br,{className:"h-4 w-4"}),"麦麦状态"]})}),e.jsx(Ts,{children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("div",{className:"flex items-center gap-2",children:O?.running?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-3 w-3 rounded-full bg-green-500 animate-pulse"}),e.jsxs($e,{variant:"outline",className:"text-green-600 border-green-300 bg-green-50",children:[e.jsx(fa,{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($e,{variant:"outline",className:"text-red-600 border-red-300 bg-red-50",children:[e.jsx(Sa,{className:"h-3 w-3 mr-1"}),"已停止"]})]})}),O&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:[e.jsxs("span",{children:["v",O.version]}),e.jsx("span",{className:"mx-2",children:"|"}),e.jsxs("span",{children:["运行 ",je(O.uptime)]})]})]})})]}),e.jsxs(Ze,{className:"lg:col-span-2",children:[e.jsx(ys,{className:"pb-3",children:e.jsxs(ws,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(cn,{className:"h-4 w-4"}),"快速操作"]})}),e.jsx(Ts,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:$,disabled:L,className:"gap-2",children:[e.jsx(Zc,{className:`h-4 w-4 ${L?"animate-spin":""}`}),L?"重启中...":"重启麦麦"]}),e.jsx(N,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Yc,{to:"/logs",children:[e.jsx(Ra,{className:"h-4 w-4"}),"查看日志"]})}),e.jsx(N,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Yc,{to:"/plugins",children:[e.jsx(mb,{className:"h-4 w-4"}),"插件管理"]})}),e.jsx(N,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Yc,{to:"/settings",children:[e.jsx(oi,{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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"总请求数"}),e.jsx(hb,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-2xl font-bold",children:Se.total_requests.toLocaleString()}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["最近",x<48?x+"小时":Math.floor(x/24)+"天"]})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"总花费"}),e.jsx(xb,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:["¥",Se.total_cost.toFixed(2)]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:Se.cost_per_hour>0?`¥${Se.cost_per_hour.toFixed(2)}/小时`:"暂无数据"})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"Token消耗"}),e.jsx(Ic,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[(Se.total_tokens/1e3).toFixed(1),"K"]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:Se.tokens_per_hour>0?`${(Se.tokens_per_hour/1e3).toFixed(1)}K/小时`:"暂无数据"})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"平均响应"}),e.jsx(cn,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[Se.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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"在线时长"}),e.jsx(li,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(Ts,{children:e.jsx("div",{className:"text-xl font-bold",children:je(Se.online_time)})})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"消息处理"}),e.jsx(un,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-xl font-bold",children:Se.total_messages.toLocaleString()}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["回复 ",Se.total_replies.toLocaleString()," 条"]})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"成本效率"}),e.jsx(fb,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-xl font-bold",children:Se.total_messages>0?`¥${(Se.total_cost/Se.total_messages*100).toFixed(2)}`:"¥0.00"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"每100条消息"})]})]})]}),e.jsxs(Ca,{defaultValue:"trends",className:"space-y-4",children:[e.jsxs(pa,{className:"grid w-full grid-cols-2 sm:grid-cols-4",children:[e.jsx(ns,{value:"trends",children:"趋势"}),e.jsx(ns,{value:"models",children:"模型"}),e.jsx(ns,{value:"activity",children:"活动"}),e.jsx(ns,{value:"daily",children:"日统计"})]}),e.jsxs(Es,{value:"trends",className:"space-y-4",children:[e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"请求趋势"}),e.jsxs(ct,{children:["最近",x,"小时的请求量变化"]})]}),e.jsx(Ts,{children:e.jsx(si,{config:K,className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(FN,{data:ne,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:E=>ye(E),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:E=>ye(E)})}),e.jsx($N,{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(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"花费趋势"}),e.jsx(ct,{children:"API调用成本变化"})]}),e.jsx(Ts,{children:e.jsx(si,{config:K,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(bu,{data:ne,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:E=>ye(E),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:E=>ye(E)})}),e.jsx(Gc,{dataKey:"cost",fill:"var(--color-cost)"})]})})})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"Token消耗"}),e.jsx(ct,{children:"Token使用量变化"})]}),e.jsx(Ts,{children:e.jsx(si,{config:K,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(bu,{data:ne,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:E=>ye(E),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:E=>ye(E)})}),e.jsx(Gc,{dataKey:"tokens",fill:"var(--color-tokens)"})]})})})]})]})]}),e.jsx(Es,{value:"models",className:"space-y-4",children:e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:[e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"模型请求分布"}),e.jsxs(ct,{children:["各模型使用占比 (共 ",M.length," 个模型)"]})]}),e.jsx(Ts,{children:e.jsx(si,{config:Object.fromEntries(M.map((E,se)=>[E.model_name,{label:E.model_name,color:be[se]}])),className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(QN,{children:[e.jsx(ir,{content:e.jsx(ti,{})}),e.jsx(YN,{data:A,cx:"50%",cy:"50%",labelLine:!1,label:({name:E,percent:se})=>se&&se<.05?"":`${E} ${se?(se*100).toFixed(0):0}%`,outerRadius:100,dataKey:"value",children:A.map((E,se)=>e.jsx(XN,{fill:E.fill},`cell-${se}`))})]})})})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"模型详细统计"}),e.jsx(ct,{children:"请求数、花费和性能"})]}),e.jsx(Ts,{children:e.jsx(ss,{className:"h-[300px] sm:h-[400px]",children:e.jsx("div",{className:"space-y-3",children:M.map((E,se)=>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:E.model_name}),e.jsx("div",{className:"w-3 h-3 rounded-full ml-2 flex-shrink-0",style:{backgroundColor:`hsl(var(--chart-${se%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:E.request_count.toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1 font-medium",children:["¥",E.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:[(E.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:[E.avg_response_time.toFixed(2),"s"]})]})]})]},se))})})})]})]})}),e.jsx(Es,{value:"activity",children:e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"最近活动"}),e.jsx(ct,{children:"最新的API调用记录"})]}),e.jsx(Ts,{children:e.jsx(ss,{className:"h-[400px] sm:h-[500px]",children:e.jsx("div",{className:"space-y-2",children:_e.map((E,se)=>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:E.model}),e.jsx("div",{className:"text-xs text-muted-foreground",children:E.request_type})]}),e.jsx("div",{className:"text-xs text-muted-foreground flex-shrink-0",children:ye(E.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:E.tokens})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1",children:["¥",E.cost.toFixed(4)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"耗时:"}),e.jsxs("span",{className:"ml-1",children:[E.time_cost.toFixed(2),"s"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"状态:"}),e.jsx("span",{className:`ml-1 ${E.status==="success"?"text-green-600":"text-red-600"}`,children:E.status})]})]})]},se))})})})]})}),e.jsx(Es,{value:"daily",children:e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"每日统计"}),e.jsx(ct,{children:"最近7天的数据汇总"})]}),e.jsx(Ts,{children:e.jsx(si,{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(bu,{data:fe,children:[e.jsx(Hc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(qc,{dataKey:"timestamp",tickFormatter:E=>{const se=new Date(E);return`${se.getMonth()+1}/${se.getDate()}`},stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{yAxisId:"left",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(lr,{yAxisId:"right",orientation:"right",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ir,{content:e.jsx(ti,{labelFormatter:E=>new Date(E).toLocaleDateString("zh-CN")})}),e.jsx(Ay,{content:e.jsx(wg,{})}),e.jsx(Gc,{yAxisId:"left",dataKey:"requests",fill:"var(--color-requests)"}),e.jsx(Gc,{yAxisId:"right",dataKey:"cost",fill:"var(--color-cost)"})]})})})]})})]})]})})}const qy={theme:"system",setTheme:()=>null},_g=u.createContext(qy),Xu=()=>{const n=u.useContext(_g);if(n===void 0)throw new Error("useTheme must be used within a ThemeProvider");return n},Gy=(n,i,c)=>{const d=document.documentElement.classList.contains("no-animations");if(!document.startViewTransition||d){i(n);return}const h=c.clientX,f=c.clientY,x=Math.hypot(Math.max(h,innerWidth-h),Math.max(f,innerHeight-f));document.startViewTransition(()=>{i(n)}).ready.then(()=>{document.documentElement.animate({clipPath:[`circle(0px at ${h}px ${f}px)`,`circle(${x}px at ${h}px ${f}px)`]},{duration:500,easing:"ease-in-out",pseudoElement:"::view-transition-new(root)"})})},Sg=u.createContext(void 0),Cg=()=>{const n=u.useContext(Sg);if(n===void 0)throw new Error("useAnimation must be used within an AnimationProvider");return n},Qe=u.forwardRef(({className:n,...i},c)=>e.jsx(Ep,{className:X("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),...i,ref:c,children:e.jsx(kN,{className:X("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")})}));Qe.displayName=Ep.displayName;const Vy=ci("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"),b=u.forwardRef(({className:n,...i},c)=>e.jsx(Vp,{ref:c,className:X(Vy(),n),...i}));b.displayName=Vp.displayName;const ie=u.forwardRef(({className:n,type:i,...c},d)=>e.jsx("input",{type:i,className:X("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,...c}));ie.displayName="Input";const Fy=[{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 $y(n){const i=Fy.map(d=>({id:d.id,label:d.label,description:d.description,passed:d.validate(n)}));return{isValid:i.every(d=>d.passed),rules:i}}const Ku="0.11.7 Beta",Ju="MaiBot Dashboard",Qy=`${Ju} v${Ku}`,Yy=(n="v")=>`${n}${Ku}`,Ft={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"},Oa={theme:"system",accentColor:"blue",enableAnimations:!0,enableWavesBackground:!0,logCacheSize:1e3,logAutoScroll:!0,logFontSize:"xs",logLineSpacing:4,dataSyncInterval:30,wsReconnectInterval:3e3,wsMaxReconnectAttempts:10};function st(n){const i=kg(n),c=localStorage.getItem(i);if(c===null)return Oa[n];const d=Oa[n];if(typeof d=="boolean")return c==="true";if(typeof d=="number"){const h=parseFloat(c);return isNaN(h)?d:h}return c}function ai(n,i){const c=kg(n);localStorage.setItem(c,String(i)),window.dispatchEvent(new CustomEvent("maibot-settings-change",{detail:{key:n,value:i}}))}function Xy(){return{theme:st("theme"),accentColor:st("accentColor"),enableAnimations:st("enableAnimations"),enableWavesBackground:st("enableWavesBackground"),logCacheSize:st("logCacheSize"),logAutoScroll:st("logAutoScroll"),logFontSize:st("logFontSize"),logLineSpacing:st("logLineSpacing"),dataSyncInterval:st("dataSyncInterval"),wsReconnectInterval:st("wsReconnectInterval"),wsMaxReconnectAttempts:st("wsMaxReconnectAttempts")}}function Ky(){const n=Xy(),i=localStorage.getItem(Ft.COMPLETED_TOURS),c=i?JSON.parse(i):[];return{...n,completedTours:c}}function Jy(n){const i=[],c=[];for(const[d,h]of Object.entries(n)){if(d==="completedTours"){Array.isArray(h)?(localStorage.setItem(Ft.COMPLETED_TOURS,JSON.stringify(h)),i.push("completedTours")):c.push("completedTours");continue}if(d in Oa){const f=d,x=Oa[f];if(typeof h==typeof x){if(f==="theme"&&!["light","dark","system"].includes(h)){c.push(d);continue}if(f==="logFontSize"&&!["xs","sm","base"].includes(h)){c.push(d);continue}ai(f,h),i.push(d)}else c.push(d)}else c.push(d)}return{success:i.length>0,imported:i,skipped:c}}function Zy(){for(const n of Object.keys(Oa))ai(n,Oa[n]);localStorage.removeItem(Ft.COMPLETED_TOURS),window.dispatchEvent(new CustomEvent("maibot-settings-reset"))}function Iy(){const n=[],i=[],c=[];for(let d=0;dd.size-c.size),{used:n,items:localStorage.length,details:i}}function Py(n){if(n===0)return"0 B";const i=1024,c=["B","KB","MB"],d=Math.floor(Math.log(n)/Math.log(i));return parseFloat((n/Math.pow(i,d)).toFixed(2))+" "+c[d]}function kg(n){return{theme:Ft.THEME,accentColor:Ft.ACCENT_COLOR,enableAnimations:Ft.ENABLE_ANIMATIONS,enableWavesBackground:Ft.ENABLE_WAVES_BACKGROUND,logCacheSize:Ft.LOG_CACHE_SIZE,logAutoScroll:Ft.LOG_AUTO_SCROLL,logFontSize:Ft.LOG_FONT_SIZE,logLineSpacing:Ft.LOG_LINE_SPACING,dataSyncInterval:Ft.DATA_SYNC_INTERVAL,wsReconnectInterval:Ft.WS_RECONNECT_INTERVAL,wsMaxReconnectAttempts:Ft.WS_MAX_RECONNECT_ATTEMPTS}[n]}const wa=u.forwardRef(({className:n,...i},c)=>e.jsxs(zp,{ref:c,className:X("relative flex w-full touch-none select-none items-center",n),...i,children:[e.jsx(TN,{className:"relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20",children:e.jsx(EN,{className:"absolute h-full bg-primary"})}),e.jsx(zN,{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"})]}));wa.displayName=zp.displayName;class Wy{ws=null;reconnectTimeout=null;reconnectAttempts=0;heartbeatInterval=null;logCallbacks=new Set;connectionCallbacks=new Set;isConnected=!1;logCache=[];getMaxCacheSize(){return st("logCacheSize")}getMaxReconnectAttempts(){return st("wsMaxReconnectAttempts")}getReconnectInterval(){return st("wsReconnectInterval")}getWebSocketUrl(){{const i=window.location.protocol==="https:"?"wss:":"ws:",c=window.location.host;return`${i}//${c}/ws/logs`}}connect(){if(this.ws?.readyState===WebSocket.OPEN||this.ws?.readyState===WebSocket.CONNECTING)return;const i=this.getWebSocketUrl();try{this.ws=new WebSocket(i),this.ws.onopen=()=>{this.isConnected=!0,this.reconnectAttempts=0,this.notifyConnection(!0),this.startHeartbeat()},this.ws.onmessage=c=>{try{if(c.data==="pong")return;const d=JSON.parse(c.data);this.notifyLog(d)}catch(d){console.error("解析日志消息失败:",d)}},this.ws.onerror=c=>{console.error("❌ WebSocket 错误:",c),this.isConnected=!1,this.notifyConnection(!1)},this.ws.onclose=()=>{this.isConnected=!1,this.notifyConnection(!1),this.stopHeartbeat(),this.attemptReconnect()}}catch(c){console.error("创建 WebSocket 连接失败:",c),this.attemptReconnect()}}attemptReconnect(){const i=this.getMaxReconnectAttempts();if(this.reconnectAttempts>=i)return;this.reconnectAttempts+=1;const c=this.getReconnectInterval(),d=Math.min(c*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(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(d=>d.id===i.id)){this.logCache.push(i);const d=this.getMaxCacheSize();this.logCache.length>d&&(this.logCache=this.logCache.slice(-d)),this.logCallbacks.forEach(h=>{try{h(i)}catch(f){console.error("日志回调执行失败:",f)}})}}notifyConnection(i){this.connectionCallbacks.forEach(c=>{try{c(i)}catch(d){console.error("连接状态回调执行失败:",d)}})}getAllLogs(){return[...this.logCache]}clearLogs(){this.logCache=[]}getConnectionStatus(){return this.isConnected}}const rn=new Wy;typeof window<"u"&&rn.connect();const $s=IN,Zu=PN,e0=JN,Tg=u.forwardRef(({className:n,...i},c)=>e.jsx(Fp,{ref:c,className:X("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),...i}));Tg.displayName=Fp.displayName;const Hs=u.forwardRef(({className:n,children:i,preventOutsideClose:c=!1,...d},h)=>e.jsxs(e0,{children:[e.jsx(Tg,{}),e.jsxs($p,{ref:h,className:X("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:c?f=>f.preventDefault():void 0,onInteractOutside:c?f=>f.preventDefault():void 0,...d,children:[i,e.jsxs(ZN,{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(dl,{className:"h-4 w-4"}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Hs.displayName=$p.displayName;const qs=({className:n,...i})=>e.jsx("div",{className:X("flex flex-col space-y-1.5 text-center sm:text-left",n),...i});qs.displayName="DialogHeader";const at=({className:n,...i})=>e.jsx("div",{className:X("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",n),...i});at.displayName="DialogFooter";const Gs=u.forwardRef(({className:n,...i},c)=>e.jsx(Qp,{ref:c,className:X("text-lg font-semibold leading-none tracking-tight",n),...i}));Gs.displayName=Qp.displayName;const Is=u.forwardRef(({className:n,...i},c)=>e.jsx(Yp,{ref:c,className:X("text-sm text-muted-foreground",n),...i}));Is.displayName=Yp.displayName;const ps=MN,tt=DN,s0=AN,Eg=u.forwardRef(({className:n,...i},c)=>e.jsx(Ap,{className:X("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),...i,ref:c}));Eg.displayName=Ap.displayName;const rs=u.forwardRef(({className:n,...i},c)=>e.jsxs(s0,{children:[e.jsx(Eg,{}),e.jsx(Mp,{ref:c,className:X("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),...i})]}));rs.displayName=Mp.displayName;const cs=({className:n,...i})=>e.jsx("div",{className:X("flex flex-col space-y-2 text-center sm:text-left",n),...i});cs.displayName="AlertDialogHeader";const os=({className:n,...i})=>e.jsx("div",{className:X("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",n),...i});os.displayName="AlertDialogFooter";const ds=u.forwardRef(({className:n,...i},c)=>e.jsx(Dp,{ref:c,className:X("text-lg font-semibold",n),...i}));ds.displayName=Dp.displayName;const us=u.forwardRef(({className:n,...i},c)=>e.jsx(Op,{ref:c,className:X("text-sm text-muted-foreground",n),...i}));us.displayName=Op.displayName;const ms=u.forwardRef(({className:n,...i},c)=>e.jsx(Rp,{ref:c,className:X(gr(),n),...i}));ms.displayName=Rp.displayName;const hs=u.forwardRef(({className:n,...i},c)=>e.jsx(Lp,{ref:c,className:X(gr({variant:"outline"}),"mt-2 sm:mt-0",n),...i}));hs.displayName=Lp.displayName;function t0(){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(Ca,{defaultValue:"appearance",className:"w-full",children:[e.jsxs(pa,{className:"grid w-full grid-cols-2 sm:grid-cols-4 gap-0.5 sm:gap-1 h-auto p-1",children:[e.jsxs(ns,{value:"appearance",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(pb,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"外观"})]}),e.jsxs(ns,{value:"security",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(gb,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"安全"})]}),e.jsxs(ns,{value:"other",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(oi,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"其他"})]}),e.jsxs(ns,{value:"about",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(La,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"关于"})]})]}),e.jsxs(ss,{className:"h-[calc(100vh-240px)] sm:h-[calc(100vh-280px)] mt-4 sm:mt-6",children:[e.jsx(Es,{value:"appearance",className:"mt-0",children:e.jsx(a0,{})}),e.jsx(Es,{value:"security",className:"mt-0",children:e.jsx(l0,{})}),e.jsx(Es,{value:"other",className:"mt-0",children:e.jsx(n0,{})}),e.jsx(Es,{value:"about",className:"mt-0",children:e.jsx(i0,{})})]})]})]})}function np(n){const i=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)i.style.setProperty("--primary",d.hsl),d.gradient?(i.style.setProperty("--primary-gradient",d.gradient),i.classList.add("has-gradient")):(i.style.removeProperty("--primary-gradient"),i.classList.remove("has-gradient"));else if(n.startsWith("#")){const h=f=>{f=f.replace("#","");const x=parseInt(f.substring(0,2),16)/255,j=parseInt(f.substring(2,4),16)/255,p=parseInt(f.substring(4,6),16)/255,w=Math.max(x,j,p),v=Math.min(x,j,p);let y=0,S=0;const k=(w+v)/2;if(w!==v){const O=w-v;switch(S=k>.5?O/(2-w-v):O/(w+v),w){case x:y=((j-p)/O+(jlocalStorage.getItem("accent-color")||"blue");u.useEffect(()=>{const w=localStorage.getItem("accent-color")||"blue";np(w)},[]);const p=w=>{j(w),localStorage.setItem("accent-color",w),np(w)};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(Eu,{value:"light",current:n,onChange:i,label:"浅色",description:"始终使用浅色主题"}),e.jsx(Eu,{value:"dark",current:n,onChange:i,label:"深色",description:"始终使用深色主题"}),e.jsx(Eu,{value:"system",current:n,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(xa,{value:"blue",current:x,onChange:p,label:"蓝色",colorClass:"bg-blue-500"}),e.jsx(xa,{value:"purple",current:x,onChange:p,label:"紫色",colorClass:"bg-purple-500"}),e.jsx(xa,{value:"green",current:x,onChange:p,label:"绿色",colorClass:"bg-green-500"}),e.jsx(xa,{value:"orange",current:x,onChange:p,label:"橙色",colorClass:"bg-orange-500"}),e.jsx(xa,{value:"pink",current:x,onChange:p,label:"粉色",colorClass:"bg-pink-500"}),e.jsx(xa,{value:"red",current:x,onChange:p,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(xa,{value:"gradient-sunset",current:x,onChange:p,label:"日落",colorClass:"bg-gradient-to-r from-orange-500 to-pink-500"}),e.jsx(xa,{value:"gradient-ocean",current:x,onChange:p,label:"海洋",colorClass:"bg-gradient-to-r from-blue-500 to-cyan-500"}),e.jsx(xa,{value:"gradient-forest",current:x,onChange:p,label:"森林",colorClass:"bg-gradient-to-r from-green-500 to-emerald-500"}),e.jsx(xa,{value:"gradient-aurora",current:x,onChange:p,label:"极光",colorClass:"bg-gradient-to-r from-purple-500 to-pink-500"}),e.jsx(xa,{value:"gradient-fire",current:x,onChange:p,label:"烈焰",colorClass:"bg-gradient-to-r from-red-500 to-orange-500"}),e.jsx(xa,{value:"gradient-twilight",current:x,onChange:p,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:x.startsWith("#")?x:"#3b82f6",onChange:w=>p(w.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:x,onChange:w=>p(w.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(b,{htmlFor:"animations",className:"text-base font-medium cursor-pointer",children:"启用动画效果"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后将禁用所有过渡动画和特效,提升性能"})]}),e.jsx(Qe,{id:"animations",checked:c,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(b,{htmlFor:"waves-background",className:"text-base font-medium cursor-pointer",children:"登录页波浪背景"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后登录页将使用纯色背景,适合低性能设备"})]}),e.jsx(Qe,{id:"waves-background",checked:h,onCheckedChange:f})]})})]})]})]})}function l0(){const n=ja(),[i,c]=u.useState(""),[d,h]=u.useState(""),[f,x]=u.useState(!1),[j,p]=u.useState(!1),[w,v]=u.useState(!1),[y,S]=u.useState(!1),[k,O]=u.useState(!1),[Y,L]=u.useState(!1),[R,H]=u.useState(""),[D,C]=u.useState(!1),{toast:$}=Vs(),G=u.useMemo(()=>$y(d),[d]),T=async je=>{if(!i){$({title:"无法复制",description:"Token 存储在安全 Cookie 中,请重新生成以获取新 Token",variant:"destructive"});return}try{await navigator.clipboard.writeText(je),O(!0),$({title:"复制成功",description:"Token 已复制到剪贴板"}),setTimeout(()=>O(!1),2e3)}catch{$({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},M=async()=>{if(!d.trim()){$({title:"输入错误",description:"请输入新的 Token",variant:"destructive"});return}if(!G.isValid){const je=G.rules.filter(ye=>!ye.passed).map(ye=>ye.label).join(", ");$({title:"格式错误",description:`Token 不符合要求: ${je}`,variant:"destructive"});return}v(!0);try{const je=await fetch("/api/webui/auth/update",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({new_token:d.trim()})}),ye=await je.json();je.ok&&ye.success?(h(""),c(d.trim()),$({title:"更新成功",description:"Access Token 已更新,即将跳转到登录页"}),setTimeout(()=>{n({to:"/auth"})},1500)):$({title:"更新失败",description:ye.message||"无法更新 Token",variant:"destructive"})}catch(je){console.error("更新 Token 错误:",je),$({title:"更新失败",description:"连接服务器失败",variant:"destructive"})}finally{v(!1)}},ne=async()=>{S(!0);try{const je=await fetch("/api/webui/auth/regenerate",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include"}),ye=await je.json();je.ok&&ye.success?(c(ye.token),H(ye.token),L(!0),C(!1),$({title:"生成成功",description:"新的 Access Token 已生成,请及时保存"})):$({title:"生成失败",description:ye.message||"无法生成新 Token",variant:"destructive"})}catch(je){console.error("生成 Token 错误:",je),$({title:"生成失败",description:"连接服务器失败",variant:"destructive"})}finally{S(!1)}},fe=async()=>{try{await navigator.clipboard.writeText(R),C(!0),$({title:"复制成功",description:"Token 已复制到剪贴板"})}catch{$({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},_e=()=>{L(!1),setTimeout(()=>{H(""),C(!1)},300),setTimeout(()=>{n({to:"/auth"})},500)},Se=je=>{je||_e()};return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsx($s,{open:Y,onOpenChange:Se,children:e.jsxs(Hs,{className:"sm:max-w-md",children:[e.jsxs(qs,{children:[e.jsxs(Gs,{className:"flex items-center gap-2",children:[e.jsx(_a,{className:"h-5 w-5 text-yellow-500"}),"新的 Access Token"]}),e.jsx(Is,{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(b,{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:R})]}),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(_a,{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(N,{variant:"outline",onClick:fe,className:"gap-2",children:D?e.jsxs(e.Fragment,{children:[e.jsx($t,{className:"h-4 w-4 text-green-500"}),"已复制"]}):e.jsxs(e.Fragment,{children:[e.jsx(Pc,{className:"h-4 w-4"}),"复制 Token"]})}),e.jsx(N,{onClick:_e,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(b,{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:f?"text":"password",value:i||"••••••••••••••••••••••••••••••••",readOnly:!0,className:"pr-10 font-mono text-sm",placeholder:"Token 存储在安全 Cookie 中"}),e.jsx("button",{onClick:()=>{i?x(!f):$({title:"无法查看",description:'Token 存储在安全 Cookie 中,如需新 Token 请点击"重新生成"'})},className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:f?"隐藏":"显示",children:f?e.jsx(xr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Dt,{className:"h-4 w-4 text-muted-foreground"})})]}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[e.jsx(N,{variant:"outline",size:"icon",onClick:()=>T(i),title:"复制到剪贴板",className:"flex-shrink-0",disabled:!i,children:k?e.jsx($t,{className:"h-4 w-4 text-green-500"}):e.jsx(Pc,{className:"h-4 w-4"})}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",disabled:y,className:"gap-2 flex-1 sm:flex-none",children:[e.jsx(Ct,{className:X("h-4 w-4",y&&"animate-spin")}),e.jsx("span",{className:"hidden sm:inline",children:"重新生成"}),e.jsx("span",{className:"sm:hidden",children:"生成"})]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认重新生成 Token"}),e.jsx(us,{children:"这将生成一个新的 64 位安全令牌,并使当前 Token 立即失效。 您需要使用新 Token 重新登录系统。此操作不可撤销,确定要继续吗?"})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:ne,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(b,{htmlFor:"new-token",className:"text-sm",children:"新的访问令牌"}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{id:"new-token",type:j?"text":"password",value:d,onChange:je=>h(je.target.value),className:"pr-10 font-mono text-sm",placeholder:"输入自定义 Token"}),e.jsx("button",{onClick:()=>p(!j),className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:j?"隐藏":"显示",children:j?e.jsx(xr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Dt,{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:G.rules.map(je=>e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[je.passed?e.jsx(fa,{className:"h-4 w-4 text-green-500 flex-shrink-0"}):e.jsx(cg,{className:"h-4 w-4 text-muted-foreground flex-shrink-0"}),e.jsx("span",{className:X(je.passed?"text-green-600 dark:text-green-400":"text-muted-foreground"),children:je.label})]},je.id))}),G.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($t,{className:"h-4 w-4"}),e.jsx("span",{className:"font-medium",children:"Token 格式正确,可以使用"})]})})]})]}),e.jsx(N,{onClick:M,disabled:w||!G.isValid||!d,className:"w-full sm:w-auto",children:w?"更新中...":"更新自定义 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 n0(){const n=ja(),{toast:i}=Vs(),[c,d]=u.useState(!1),[h,f]=u.useState(!1),[x,j]=u.useState(()=>st("logCacheSize")),[p,w]=u.useState(()=>st("wsReconnectInterval")),[v,y]=u.useState(()=>st("wsMaxReconnectAttempts")),[S,k]=u.useState(()=>st("dataSyncInterval")),[O,Y]=u.useState(()=>lp()),[L,R]=u.useState(!1),[H,D]=u.useState(!1),C=u.useRef(null);if(h)throw new Error("这是一个手动触发的测试错误,用于验证错误边界组件是否正常工作。");const $=()=>{Y(lp())},G=A=>{const K=A[0];j(K),ai("logCacheSize",K)},T=A=>{const K=A[0];w(K),ai("wsReconnectInterval",K)},M=A=>{const K=A[0];y(K),ai("wsMaxReconnectAttempts",K)},ne=A=>{const K=A[0];k(K),ai("dataSyncInterval",K)},fe=()=>{rn.clearLogs(),i({title:"日志已清除",description:"日志缓存已清空"})},_e=()=>{const A=Iy();$(),i({title:"缓存已清除",description:`已清除 ${A.clearedKeys.length} 项缓存数据`})},Se=()=>{R(!0);try{const A=Ky(),K=JSON.stringify(A,null,2),E=new Blob([K],{type:"application/json"}),se=URL.createObjectURL(E),_=document.createElement("a");_.href=se,_.download=`maibot-webui-settings-${new Date().toISOString().slice(0,10)}.json`,document.body.appendChild(_),_.click(),document.body.removeChild(_),URL.revokeObjectURL(se),i({title:"导出成功",description:"设置已导出为 JSON 文件"})}catch(A){console.error("导出设置失败:",A),i({title:"导出失败",description:"无法导出设置",variant:"destructive"})}finally{R(!1)}},je=A=>{const K=A.target.files?.[0];if(!K)return;D(!0);const E=new FileReader;E.onload=se=>{try{const _=se.target?.result,me=JSON.parse(_),re=Jy(me);re.success?(j(st("logCacheSize")),w(st("wsReconnectInterval")),y(st("wsMaxReconnectAttempts")),k(st("dataSyncInterval")),$(),i({title:"导入成功",description:`成功导入 ${re.imported.length} 项设置${re.skipped.length>0?`,跳过 ${re.skipped.length} 项`:""}`}),(re.imported.includes("theme")||re.imported.includes("accentColor"))&&i({title:"提示",description:"部分设置需要刷新页面才能完全生效"})):i({title:"导入失败",description:"没有有效的设置项可导入",variant:"destructive"})}catch(_){console.error("导入设置失败:",_),i({title:"导入失败",description:"文件格式无效",variant:"destructive"})}finally{D(!1),C.current&&(C.current.value="")}},E.readAsText(K)},ye=()=>{Zy(),j(Oa.logCacheSize),w(Oa.wsReconnectInterval),y(Oa.wsMaxReconnectAttempts),k(Oa.dataSyncInterval),$(),i({title:"已重置",description:"所有设置已恢复为默认值,刷新页面以应用更改"})},be=async()=>{d(!0);try{const A=localStorage.getItem("access-token"),K=await fetch("/api/webui/setup/reset",{method:"POST",headers:{Authorization:`Bearer ${A}`}}),E=await K.json();K.ok&&E.success?(i({title:"重置成功",description:"即将进入初次配置向导"}),setTimeout(()=>{n({to:"/setup"})},1e3)):i({title:"重置失败",description:E.message||"无法重置配置状态",variant:"destructive"})}catch(A){console.error("重置配置状态错误:",A),i({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(Ic,{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(jb,{className:"h-4 w-4"}),"本地存储使用"]}),e.jsx(N,{variant:"ghost",size:"sm",onClick:$,className:"h-7 px-2",children:e.jsx(Ct,{className:"h-3 w-3"})})]}),e.jsx("div",{className:"text-2xl font-bold text-primary",children:Py(O.used)}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:[O.items," 个存储项"]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{className:"text-sm font-medium",children:"日志缓存大小"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[x," 条"]})]}),e.jsx(wa,{value:[x],onValueChange:G,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(b,{className:"text-sm font-medium",children:"首页数据刷新间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[S," 秒"]})]}),e.jsx(wa,{value:[S],onValueChange:ne,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(b,{className:"text-sm font-medium",children:"WebSocket 重连间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[p/1e3," 秒"]})]}),e.jsx(wa,{value:[p],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(b,{className:"text-sm font-medium",children:"WebSocket 最大重连次数"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[v," 次"]})]}),e.jsx(wa,{value:[v],onValueChange:M,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(N,{variant:"outline",size:"sm",onClick:fe,className:"gap-2",children:[e.jsx(ts,{className:"h-4 w-4"}),"清除日志缓存"]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:"gap-2",children:[e.jsx(ts,{className:"h-4 w-4"}),"清除本地缓存"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认清除本地缓存"}),e.jsx(us,{children:"这将清除所有本地缓存的设置和数据(不包括登录凭证)。 您可能需要重新配置部分偏好设置。确定要继续吗?"})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:_e,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(rl,{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(N,{variant:"outline",onClick:Se,disabled:L,className:"gap-2",children:[e.jsx(rl,{className:"h-4 w-4"}),L?"导出中...":"导出设置"]}),e.jsx("input",{ref:C,type:"file",accept:".json",onChange:je,className:"hidden"}),e.jsxs(N,{variant:"outline",onClick:()=>C.current?.click(),disabled:H,className:"gap-2",children:[e.jsx(fr,{className:"h-4 w-4"}),H?"导入中...":"导入设置"]})]}),e.jsx("div",{className:"pt-2 border-t",children:e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:"gap-2 text-destructive hover:text-destructive",children:[e.jsx(Zc,{className:"h-4 w-4"}),"重置所有设置为默认值"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认重置所有设置"}),e.jsx(us,{children:"这将把所有界面设置恢复为默认值,包括主题、颜色、动画等偏好设置。 此操作不会影响您的登录状态。确定要继续吗?"})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:ye,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(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"outline",disabled:c,className:"gap-2",children:[e.jsx(Zc,{className:X("h-4 w-4",c&&"animate-spin")}),"重新进行初次配置"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认重新配置"}),e.jsx(us,{children:"这将带您重新进入初次配置向导。您可以重新设置系统的基础配置项。确定要继续吗?"})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{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(_a,{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(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{variant:"destructive",className:"gap-2",children:[e.jsx(_a,{className:"h-4 w-4"}),"触发测试错误"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认触发错误"}),e.jsx(us,{children:"这将手动触发一个 React 错误,用于测试错误边界组件的显示效果。 页面将显示错误界面,您可以通过刷新页面或点击返回首页来恢复。"})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>f(!0),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认触发"})]})]})]})]})]})]})}function i0(){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:X("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:["关于 ",Ju]}),e.jsxs("div",{className:"space-y-2 text-xs sm:text-sm text-muted-foreground",children:[e.jsxs("p",{children:["版本: ",Ku]}),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(ss,{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(Zs,{name:"React",description:"用户界面构建库",license:"MIT"}),e.jsx(Zs,{name:"shadcn/ui",description:"优雅的 React 组件库",license:"MIT"}),e.jsx(Zs,{name:"Radix UI",description:"无样式的可访问组件库",license:"MIT"}),e.jsx(Zs,{name:"Tailwind CSS",description:"实用优先的 CSS 框架",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"TanStack Router",description:"类型安全的路由库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"React Hook Form",description:"高性能表单库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"clsx",description:"条件 className 构建工具",license:"MIT"}),e.jsx(Zs,{name:"tailwind-merge",description:"Tailwind 类名合并工具",license:"MIT"}),e.jsx(Zs,{name:"class-variance-authority",description:"组件变体管理",license:"Apache-2.0"}),e.jsx(Zs,{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(Zs,{name:"Framer Motion",description:"React 动画库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"FastAPI",description:"现代化 Python Web 框架",license:"MIT"}),e.jsx(Zs,{name:"Uvicorn",description:"ASGI 服务器",license:"BSD-3-Clause"}),e.jsx(Zs,{name:"Pydantic",description:"数据验证库",license:"MIT"}),e.jsx(Zs,{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(Zs,{name:"TypeScript",description:"JavaScript 的超集",license:"Apache-2.0"}),e.jsx(Zs,{name:"Vite",description:"下一代前端构建工具",license:"MIT"}),e.jsx(Zs,{name:"ESLint",description:"JavaScript 代码检查工具",license:"MIT"}),e.jsx(Zs,{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 Zs({name:n,description:i,license:c}){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: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:c})]})}function Eu({value:n,current:i,onChange:c,label:d,description:h}){const f=i===n;return e.jsxs("button",{onClick:()=>c(n),className:X("relative rounded-lg border-2 p-3 sm:p-4 text-left transition-all","hover:border-primary/50 hover:bg-accent/50",f?"border-primary bg-accent":"border-border"),children:[f&&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:h})]}),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 xa({value:n,current:i,onChange:c,label:d,colorClass:h}){const f=i===n;return e.jsxs("button",{onClick:()=>c(n),className:X("relative rounded-lg border-2 p-2 sm:p-3 text-left transition-all","hover:border-primary/50 hover:bg-accent/50",f?"border-primary bg-accent":"border-border"),children:[f&&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:X("h-8 w-8 sm:h-10 sm:w-10 rounded-full",h)}),e.jsx("div",{className:"text-[10px] sm:text-xs font-medium text-center",children:d})]})]})}class r0{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 c=0;c<256;c++)this.p[c]=Math.floor(Math.random()*256);this.perm=[];for(let c=0;c<512;c++)this.perm[c]=this.p[c&255]}dot(i,c,d){return i[0]*c+i[1]*d}mix(i,c,d){return(1-d)*i+d*c}fade(i){return i*i*i*(i*(i*6-15)+10)}perlin2(i,c){const d=Math.floor(i)&255,h=Math.floor(c)&255;i-=Math.floor(i),c-=Math.floor(c);const f=this.fade(i),x=this.fade(c),j=this.perm[d]+h,p=this.perm[j],w=this.perm[j+1],v=this.perm[d+1]+h,y=this.perm[v],S=this.perm[v+1];return this.mix(this.mix(this.dot(this.grad3[p%12],i,c),this.dot(this.grad3[y%12],i-1,c),f),this.mix(this.dot(this.grad3[w%12],i,c-1),this.dot(this.grad3[S%12],i-1,c-1),f),x)}}function ip(){const n=u.useRef(null),i=u.useRef(null),c=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 r0(Math.random()),bounding:null});return u.useEffect(()=>{const h=i.current,f=n.current;if(!h||!f)return;const x=d.current,j=()=>{const Y=h.getBoundingClientRect();x.bounding=Y,f.style.width=`${Y.width}px`,f.style.height=`${Y.height}px`},p=()=>{if(!x.bounding)return;const{width:Y,height:L}=x.bounding;x.lines=[],x.paths.forEach(ne=>ne.remove()),x.paths=[];const R=10,H=32,D=Y+200,C=L+30,$=Math.ceil(D/R),G=Math.ceil(C/H),T=(Y-R*$)/2,M=(L-H*G)/2;for(let ne=0;ne<=$;ne++){const fe=[];for(let Se=0;Se<=G;Se++){const je={x:T+R*ne,y:M+H*Se,wave:{x:0,y:0},cursor:{x:0,y:0,vx:0,vy:0}};fe.push(je)}const _e=document.createElementNS("http://www.w3.org/2000/svg","path");f.appendChild(_e),x.paths.push(_e),x.lines.push(fe)}},w=Y=>{const{lines:L,mouse:R,noise:H}=x;L.forEach(D=>{D.forEach(C=>{const $=H.perlin2((C.x+Y*.0125)*.002,(C.y+Y*.005)*.0015)*12;C.wave.x=Math.cos($)*32,C.wave.y=Math.sin($)*16;const G=C.x-R.sx,T=C.y-R.sy,M=Math.hypot(G,T),ne=Math.max(175,R.vs);if(M{const R={x:Y.x+Y.wave.x+(L?Y.cursor.x:0),y:Y.y+Y.wave.y+(L?Y.cursor.y:0)};return R.x=Math.round(R.x*10)/10,R.y=Math.round(R.y*10)/10,R},y=()=>{const{lines:Y,paths:L}=x;Y.forEach((R,H)=>{let D=v(R[0],!1),C=`M ${D.x} ${D.y}`;R.forEach(($,G)=>{const T=G===R.length-1;D=v($,!T),C+=`L ${D.x} ${D.y}`}),L[H].setAttribute("d",C)})},S=Y=>{const{mouse:L}=x;L.sx+=(L.x-L.sx)*.1,L.sy+=(L.y-L.sy)*.1;const R=L.x-L.lx,H=L.y-L.ly,D=Math.hypot(R,H);L.v=D,L.vs+=(D-L.vs)*.1,L.vs=Math.min(100,L.vs),L.lx=L.x,L.ly=L.y,L.a=Math.atan2(H,R),h&&(h.style.setProperty("--x",`${L.sx}px`),h.style.setProperty("--y",`${L.sy}px`)),w(Y),y(),c.current=requestAnimationFrame(S)},k=Y=>{if(!x.bounding)return;const{mouse:L}=x;L.x=Y.pageX-x.bounding.left,L.y=Y.pageY-x.bounding.top+window.scrollY,L.set||(L.sx=L.x,L.sy=L.y,L.lx=L.x,L.ly=L.y,L.set=!0)},O=()=>{j(),p()};return j(),p(),window.addEventListener("resize",O),window.addEventListener("mousemove",k),c.current=requestAnimationFrame(S),()=>{window.removeEventListener("resize",O),window.removeEventListener("mousemove",k),c.current&&cancelAnimationFrame(c.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: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 Te(n,i){const c={...i,credentials:"include",headers:{"Content-Type":"application/json",...i?.headers}},d=await fetch(n,c);if(d.status===401)throw window.location.href="/auth",new Error("认证失败,请重新登录");return d}function Ls(){return{"Content-Type":"application/json"}}async function l0(){try{await fetch("/api/webui/auth/logout",{method:"POST",credentials:"include"})}catch(n){console.error("登出请求失败:",n)}window.location.href="/auth"}async function Ku(){try{return(await(await fetch("/api/webui/auth/check",{method:"GET",credentials:"include"})).json()).authenticated===!0}catch{return!1}}function n0(){const[n,i]=u.useState(""),[c,d]=u.useState(!1),[h,x]=u.useState(""),[f,j]=u.useState(!0),p=ga(),{enableWavesBackground:w,setEnableWavesBackground:v}=wg(),{theme:y,setTheme:S}=$u();u.useEffect(()=>{(async()=>{try{await Ku()&&p({to:"/"})}catch{}finally{j(!1)}})()},[p]);const M=y==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":y,F=()=>{S(M==="dark"?"light":"dark")},U=async O=>{if(O.preventDefault(),x(""),!n.trim()){x("请输入 Access Token");return}d(!0);try{const K=await fetch("/api/webui/auth/verify",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({token:n.trim()})}),H=await K.json();K.ok&&H.valid?H.is_first_setup?p({to:"/setup"}):p({to:"/"}):x(H.message||"Token 验证失败,请检查后重试")}catch(K){console.error("Token 验证错误:",K),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:[w&&e.jsx(ap,{}),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:[w&&e.jsx(ap,{}),e.jsxs(Ze,{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:F,className:"absolute right-4 top-4 rounded-lg p-2 hover:bg-accent transition-colors z-10 text-foreground",title:M==="dark"?"切换到浅色模式":"切换到深色模式",children:M==="dark"?e.jsx(ig,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"}):e.jsx(rg,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"})}),e.jsxs(ys,{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($f,{className:"h-8 w-8 text-primary",strokeWidth:2,fill:"none"})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(ws,{className:"text-2xl font-bold",children:"欢迎使用 MaiBot"}),e.jsx(ct,{className:"text-base",children:"请输入您的 Access Token 以继续访问系统"})]})]}),e.jsx(Ts,{children:e.jsxs("form",{onSubmit:U,className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"token",className:"text-sm font-medium",children:"Access Token"}),e.jsxs("div",{className:"relative",children:[e.jsx(cg,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground",strokeWidth:2,fill:"none"}),e.jsx(oe,{id:"token",type:"password",placeholder:"请输入您的 Access Token",value:n,onChange:O=>i(O.target.value),className:$("pl-10",h&&"border-red-500 focus-visible:ring-red-500"),disabled:c,autoFocus:!0,autoComplete:"off"})]})]}),h&&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(Oa,{className:"h-4 w-4 flex-shrink-0",strokeWidth:2,fill:"none"}),e.jsx("span",{children:h})]}),e.jsx(N,{type:"submit",className:"w-full",disabled:c,children:c?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($s,{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(og,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我没有 Token,我该去哪里获得 Token?"]})}),e.jsxs(Bs,{className:"sm:max-w-md",children:[e.jsxs(Hs,{children:[e.jsxs(qs,{className:"flex items-center gap-2",children:[e.jsx($f,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"如何获取 Access Token"]}),e.jsx(Is,{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(fb,{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(Da,{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(Oa,{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(ps,{children:[e.jsx(tt,{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(cn,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我觉得这个界面很卡怎么办?"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsxs(os,{className:"flex items-center gap-2",children:[e.jsx(cn,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"关闭背景动画"]}),e.jsx(ds,{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(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{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:Gy})})]})}const Fs=u.forwardRef(({className:n,...i},c)=>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:c,...i}));Fs.displayName="Textarea";const jr=u.forwardRef(({className:n,orientation:i="horizontal",decorative:c=!0,...d},h)=>e.jsx(Op,{ref:h,decorative:c,orientation:i,className:$("shrink-0 bg-border",i==="horizontal"?"h-[1px] w-full":"h-full w-[1px]",n),...d}));jr.displayName=Op.displayName;function i0({config:n,onChange:i}){const c=h=>{h.trim()&&!n.alias_names.includes(h.trim())&&i({...n,alias_names:[...n.alias_names,h.trim()]})},d=h=>{i({...n,alias_names:n.alias_names.filter((x,f)=>f!==h)})};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"qq_account",children:"QQ账号 *"}),e.jsx(oe,{id:"qq_account",type:"number",placeholder:"请输入机器人的QQ账号",value:n.qq_account||"",onChange:h=>i({...n,qq_account:Number(h.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人登录使用的QQ账号"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"nickname",children:"昵称 *"}),e.jsx(oe,{id:"nickname",placeholder:"请输入机器人的昵称",value:n.nickname,onChange:h=>i({...n,nickname:h.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的主要称呼名称"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{children:"别名"}),e.jsx("div",{className:"flex flex-wrap gap-2 mb-2",children:n.alias_names.map((h,x)=>e.jsxs(Ye,{variant:"secondary",className:"gap-1",children:[h,e.jsx("button",{type:"button",onClick:()=>d(x),className:"ml-1 hover:text-destructive",children:e.jsx(dl,{className:"h-3 w-3"})})]},x))}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(oe,{id:"alias_input",placeholder:"输入别名后按回车添加",onKeyPress:h=>{h.key==="Enter"&&(c(h.target.value),h.target.value="")}}),e.jsx(N,{type:"button",variant:"outline",onClick:()=>{const h=document.getElementById("alias_input");h&&(c(h.value),h.value="")},children:"添加"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的其他称呼,可以添加多个"})]})]})}function r0({config:n,onChange:i}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"personality",children:"人格特征 *"}),e.jsx(Fs,{id:"personality",placeholder:"描述机器人的人格特质和身份特征(建议120字以内)",value:n.personality,onChange:c=>i({...n,personality:c.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:是一个女大学生,现在在读大二,会刷贴吧"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"reply_style",children:"表达风格 *"}),e.jsx(Fs,{id:"reply_style",placeholder:"描述机器人说话的表达风格、表达习惯",value:n.reply_style,onChange:c=>i({...n,reply_style:c.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:回复平淡一些,简短一些,说中文,参考贴吧、知乎和微博的回复风格"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"interest",children:"兴趣 *"}),e.jsx(Fs,{id:"interest",placeholder:"描述机器人感兴趣的话题",value:n.interest,onChange:c=>i({...n,interest:c.target.value}),rows:2}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"会影响机器人对什么话题进行回复"})]}),e.jsx(jr,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"plan_style",children:"群聊说话规则 *"}),e.jsx(Fs,{id:"plan_style",placeholder:"机器人在群聊中的行为风格和规则",value:n.plan_style,onChange:c=>i({...n,plan_style:c.target.value}),rows:4}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在群聊中如何行动,例如回复频率、条件等"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"private_plan_style",children:"私聊说话规则 *"}),e.jsx(Fs,{id:"private_plan_style",placeholder:"机器人在私聊中的行为风格和规则",value:n.private_plan_style,onChange:c=>i({...n,private_plan_style:c.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在私聊中的行为方式"})]})]})}function c0({config:n,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(b,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(n.emoji_chance*100).toFixed(0),"%"]})]}),e.jsx(oe,{id:"emoji_chance",type:"range",min:"0",max:"1",step:"0.1",value:n.emoji_chance,onChange:c=>i({...n,emoji_chance:Number(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人发送表情包的概率"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"max_reg_num",children:"最大表情包数量"}),e.jsx(oe,{id:"max_reg_num",type:"number",min:"1",max:"200",value:n.max_reg_num,onChange:c=>i({...n,max_reg_num:Number(c.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(b,{htmlFor:"do_replace",children:"达到最大数量时替换"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"开启后会删除旧表情包,关闭则不再收集新表情包"})]}),e.jsx(Xe,{id:"do_replace",checked:n.do_replace,onCheckedChange:c=>i({...n,do_replace:c})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(oe,{id:"check_interval",type:"number",min:"1",max:"120",value:n.check_interval,onChange:c=>i({...n,check_interval:Number(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"检查表情包注册、破损、删除的时间间隔"})]}),e.jsx(jr,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"steal_emoji",children:"偷取表情包"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人将一些表情包据为己有"})]}),e.jsx(Xe,{id:"steal_emoji",checked:n.steal_emoji,onCheckedChange:c=>i({...n,steal_emoji:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"content_filtration",children:"启用表情包过滤"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只保存符合要求的表情包"})]}),e.jsx(Xe,{id:"content_filtration",checked:n.content_filtration,onCheckedChange:c=>i({...n,content_filtration:c})})]}),n.content_filtration&&e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(oe,{id:"filtration_prompt",placeholder:"例如:符合公序良俗",value:n.filtration_prompt,onChange:c=>i({...n,filtration_prompt:c.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"描述表情包应该符合的要求"})]})]})}function o0({config:n,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(b,{htmlFor:"enable_tool",children:"启用工具系统"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人使用各种工具增强功能"})]}),e.jsx(Xe,{id:"enable_tool",checked:n.enable_tool,onCheckedChange:c=>i({...n,enable_tool:c})})]}),e.jsx(jr,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"enable_mood",children:"启用情绪系统"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"让机器人具有情绪变化能力"})]}),e.jsx(Xe,{id:"enable_mood",checked:n.enable_mood,onCheckedChange:c=>i({...n,enable_mood:c})})]}),n.enable_mood&&e.jsxs("div",{className:"ml-6 space-y-6 border-l-2 border-primary/20 pl-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"mood_update_threshold",children:"情绪更新阈值"}),e.jsx(oe,{id:"mood_update_threshold",type:"number",min:"0.1",max:"10",step:"0.1",value:n.mood_update_threshold||1,onChange:c=>i({...n,mood_update_threshold:Number(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"值越高,情绪更新越慢"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"emotion_style",children:"情感特征"}),e.jsx(Fs,{id:"emotion_style",placeholder:"描述情绪的变化情况,例如:情绪较为稳定,但遭遇特定事件时起伏较大",value:n.emotion_style||"",onChange:c=>i({...n,emotion_style:c.target.value}),rows:2}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"影响机器人的情绪变化方式"})]})]}),e.jsx(jr,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"all_global",children:"启用全局黑话模式"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人学习和使用群组黑话"})]}),e.jsx(Xe,{id:"all_global",checked:n.all_global,onCheckedChange:c=>i({...n,all_global:c})})]})]})}function d0({config:n,onChange:i}){const[c,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(Xc,{className:"h-3 w-3"})]})]})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"siliconflow_api_key",children:"SiliconFlow API Key *"}),e.jsxs("div",{className:"relative",children:[e.jsx(oe,{id:"siliconflow_api_key",type:c?"text":"password",placeholder:"sk-...",value:n.api_key,onChange:h=>i({api_key:h.target.value}),className:"font-mono pr-10"}),e.jsx(N,{type:"button",variant:"ghost",size:"sm",className:"absolute right-0 top-0 h-full px-3 hover:bg-transparent",onClick:()=>d(!c),children:c?e.jsx(xr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Dt,{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 u0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取Bot配置失败");const c=(await n.json()).config.bot||{};return{qq_account:c.qq_account||0,nickname:c.nickname||"",alias_names:c.alias_names||[]}}async function m0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取人格配置失败");const c=(await n.json()).config.personality||{};return{personality:c.personality||"",reply_style:c.reply_style||"",interest:c.interest||"",plan_style:c.plan_style||"",private_plan_style:c.private_plan_style||""}}async function h0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取表情包配置失败");const c=(await n.json()).config.emoji||{};return{emoji_chance:c.emoji_chance??.4,max_reg_num:c.max_reg_num??40,do_replace:c.do_replace??!0,check_interval:c.check_interval??10,steal_emoji:c.steal_emoji??!0,content_filtration:c.content_filtration??!1,filtration_prompt:c.filtration_prompt||""}}async function x0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取其他配置失败");const c=(await n.json()).config,d=c.tool||{},h=c.mood||{},x=c.jargon||{};return{enable_tool:d.enable_tool??!0,enable_mood:h.enable_mood??!1,mood_update_threshold:h.mood_update_threshold,emotion_style:h.emotion_style,all_global:x.all_global??!0}}async function f0(){const n=await Te("/api/webui/config/model",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取模型配置失败");return{api_key:((await n.json()).config.api_providers||[]).find(x=>x.name==="SiliconFlow")?.api_key||""}}async function p0(n){const i=await Te("/api/webui/config/bot/section/bot",{method:"POST",headers:Ls(),body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"保存Bot基础配置失败")}return await i.json()}async function g0(n){const i=await Te("/api/webui/config/bot/section/personality",{method:"POST",headers:Ls(),body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"保存人格配置失败")}return await i.json()}async function j0(n){const i=await Te("/api/webui/config/bot/section/emoji",{method:"POST",headers:Ls(),body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"保存表情包配置失败")}return await i.json()}async function v0(n){const i=[];i.push(Te("/api/webui/config/bot/section/tool",{method:"POST",headers:Ls(),body:JSON.stringify({enable_tool:n.enable_tool})})),i.push(Te("/api/webui/config/bot/section/jargon",{method:"POST",headers:Ls(),body:JSON.stringify({all_global:n.all_global})}));const c={enable_mood:n.enable_mood};n.enable_mood&&(c.mood_update_threshold=n.mood_update_threshold||1,c.emotion_style=n.emotion_style||""),i.push(Te("/api/webui/config/bot/section/mood",{method:"POST",headers:Ls(),body:JSON.stringify(c)}));const d=await Promise.all(i);for(const h of d)if(!h.ok){const x=await h.json();throw new Error(x.detail||"保存其他配置失败")}return{success:!0}}async function N0(n){const i=await Te("/api/webui/config/model",{method:"GET",headers:Ls()});if(!i.ok)throw new Error("读取模型配置失败");const d=(await i.json()).config,h=d.api_providers||[],x=h.findIndex(p=>p.name==="SiliconFlow");x>=0?h[x]={...h[x],api_key:n.api_key}:h.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:h},j=await Te("/api/webui/config/model",{method:"POST",headers:Ls(),body:JSON.stringify(f)});if(!j.ok){const p=await j.json();throw new Error(p.detail||"保存模型配置失败")}return await j.json()}async function lp(){const n=localStorage.getItem("access-token"),i=await Te("/api/webui/setup/complete",{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(!i.ok){const c=await i.json();throw new Error(c.message||"标记配置完成失败")}return await i.json()}async function lo(){const n=await Te("/api/webui/system/restart",{method:"POST",headers:Ls()});if(!n.ok){const i=await n.json();throw new Error(i.detail||"重启失败")}return await n.json()}async function b0(){const n=await Te("/api/webui/system/status",{method:"GET",headers:Ls()});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取状态失败")}return await n.json()}function y0(){const n=ga(),{toast:i}=Gs(),[c,d]=u.useState(0),[h,x]=u.useState(!1),[f,j]=u.useState(!1),[p,w]=u.useState(!0),[v,y]=u.useState({qq_account:0,nickname:"",alias_names:[]}),[S,C]=u.useState({personality:"是一个女大学生,现在在读大二,会刷贴吧。",reply_style:"请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。",interest:"对技术相关话题,游戏和动漫相关话题感兴趣,也对日常话题感兴趣,不喜欢太过沉重严肃的话题",plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 + `})})]})}async function Te(n,i){const c={...i,credentials:"include",headers:{"Content-Type":"application/json",...i?.headers}},d=await fetch(n,c);if(d.status===401)throw window.location.href="/auth",new Error("认证失败,请重新登录");return d}function Ls(){return{"Content-Type":"application/json"}}async function c0(){try{await fetch("/api/webui/auth/logout",{method:"POST",credentials:"include"})}catch(n){console.error("登出请求失败:",n)}window.location.href="/auth"}async function Iu(){try{return(await(await fetch("/api/webui/auth/check",{method:"GET",credentials:"include"})).json()).authenticated===!0}catch{return!1}}function o0(){const[n,i]=u.useState(""),[c,d]=u.useState(!1),[h,f]=u.useState(""),[x,j]=u.useState(!0),p=ja(),{enableWavesBackground:w,setEnableWavesBackground:v}=Cg(),{theme:y,setTheme:S}=Xu();u.useEffect(()=>{(async()=>{try{await Iu()&&p({to:"/"})}catch{}finally{j(!1)}})()},[p]);const O=y==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":y,Y=()=>{S(O==="dark"?"light":"dark")},L=async R=>{if(R.preventDefault(),f(""),!n.trim()){f("请输入 Access Token");return}d(!0);try{const H=await fetch("/api/webui/auth/verify",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({token:n.trim()})}),D=await H.json();H.ok&&D.valid?D.is_first_setup?p({to:"/setup"}):p({to:"/"}):f(D.message||"Token 验证失败,请检查后重试")}catch(H){console.error("Token 验证错误:",H),f("连接服务器失败,请检查网络连接")}finally{d(!1)}};return x?e.jsxs("div",{className:"relative flex min-h-screen items-center justify-center overflow-hidden bg-background p-4",children:[w&&e.jsx(ip,{}),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:[w&&e.jsx(ip,{}),e.jsxs(Ze,{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:Y,className:"absolute right-4 top-4 rounded-lg p-2 hover:bg-accent transition-colors z-10 text-foreground",title:O==="dark"?"切换到浅色模式":"切换到深色模式",children:O==="dark"?e.jsx(og,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"}):e.jsx(dg,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"})}),e.jsxs(ys,{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(Xf,{className:"h-8 w-8 text-primary",strokeWidth:2,fill:"none"})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(ws,{className:"text-2xl font-bold",children:"欢迎使用 MaiBot"}),e.jsx(ct,{className:"text-base",children:"请输入您的 Access Token 以继续访问系统"})]})]}),e.jsx(Ts,{children:e.jsxs("form",{onSubmit:L,className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"token",className:"text-sm font-medium",children:"Access Token"}),e.jsxs("div",{className:"relative",children:[e.jsx(ug,{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:R=>i(R.target.value),className:X("pl-10",h&&"border-red-500 focus-visible:ring-red-500"),disabled:c,autoFocus:!0,autoComplete:"off"})]})]}),h&&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(Sa,{className:"h-4 w-4 flex-shrink-0",strokeWidth:2,fill:"none"}),e.jsx("span",{children:h})]}),e.jsx(N,{type:"submit",className:"w-full",disabled:c,children:c?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($s,{children:[e.jsx(Zu,{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(mg,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我没有 Token,我该去哪里获得 Token?"]})}),e.jsxs(Hs,{className:"sm:max-w-md",children:[e.jsxs(qs,{children:[e.jsxs(Gs,{className:"flex items-center gap-2",children:[e.jsx(Xf,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"如何获取 Access Token"]}),e.jsx(Is,{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(vb,{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(Ra,{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(Sa,{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(ps,{children:[e.jsx(tt,{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(cn,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我觉得这个界面很卡怎么办?"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsxs(ds,{className:"flex items-center gap-2",children:[e.jsx(cn,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"关闭背景动画"]}),e.jsx(us,{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(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{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:Qy})})]})}const Bs=u.forwardRef(({className:n,...i},c)=>e.jsx("textarea",{className:X("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:c,...i}));Bs.displayName="Textarea";const jr=u.forwardRef(({className:n,orientation:i="horizontal",decorative:c=!0,...d},h)=>e.jsx(Up,{ref:h,decorative:c,orientation:i,className:X("shrink-0 bg-border",i==="horizontal"?"h-[1px] w-full":"h-full w-[1px]",n),...d}));jr.displayName=Up.displayName;function d0({config:n,onChange:i}){const c=h=>{h.trim()&&!n.alias_names.includes(h.trim())&&i({...n,alias_names:[...n.alias_names,h.trim()]})},d=h=>{i({...n,alias_names:n.alias_names.filter((f,x)=>x!==h)})};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"qq_account",children:"QQ账号 *"}),e.jsx(ie,{id:"qq_account",type:"number",placeholder:"请输入机器人的QQ账号",value:n.qq_account||"",onChange:h=>i({...n,qq_account:Number(h.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人登录使用的QQ账号"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"nickname",children:"昵称 *"}),e.jsx(ie,{id:"nickname",placeholder:"请输入机器人的昵称",value:n.nickname,onChange:h=>i({...n,nickname:h.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的主要称呼名称"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{children:"别名"}),e.jsx("div",{className:"flex flex-wrap gap-2 mb-2",children:n.alias_names.map((h,f)=>e.jsxs($e,{variant:"secondary",className:"gap-1",children:[h,e.jsx("button",{type:"button",onClick:()=>d(f),className:"ml-1 hover:text-destructive",children:e.jsx(dl,{className:"h-3 w-3"})})]},f))}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{id:"alias_input",placeholder:"输入别名后按回车添加",onKeyPress:h=>{h.key==="Enter"&&(c(h.target.value),h.target.value="")}}),e.jsx(N,{type:"button",variant:"outline",onClick:()=>{const h=document.getElementById("alias_input");h&&(c(h.value),h.value="")},children:"添加"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的其他称呼,可以添加多个"})]})]})}function u0({config:n,onChange:i}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"personality",children:"人格特征 *"}),e.jsx(Bs,{id:"personality",placeholder:"描述机器人的人格特质和身份特征(建议120字以内)",value:n.personality,onChange:c=>i({...n,personality:c.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:是一个女大学生,现在在读大二,会刷贴吧"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"reply_style",children:"表达风格 *"}),e.jsx(Bs,{id:"reply_style",placeholder:"描述机器人说话的表达风格、表达习惯",value:n.reply_style,onChange:c=>i({...n,reply_style:c.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:回复平淡一些,简短一些,说中文,参考贴吧、知乎和微博的回复风格"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"interest",children:"兴趣 *"}),e.jsx(Bs,{id:"interest",placeholder:"描述机器人感兴趣的话题",value:n.interest,onChange:c=>i({...n,interest:c.target.value}),rows:2}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"会影响机器人对什么话题进行回复"})]}),e.jsx(jr,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"plan_style",children:"群聊说话规则 *"}),e.jsx(Bs,{id:"plan_style",placeholder:"机器人在群聊中的行为风格和规则",value:n.plan_style,onChange:c=>i({...n,plan_style:c.target.value}),rows:4}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在群聊中如何行动,例如回复频率、条件等"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"private_plan_style",children:"私聊说话规则 *"}),e.jsx(Bs,{id:"private_plan_style",placeholder:"机器人在私聊中的行为风格和规则",value:n.private_plan_style,onChange:c=>i({...n,private_plan_style:c.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在私聊中的行为方式"})]})]})}function m0({config:n,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(b,{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:c=>i({...n,emoji_chance:Number(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人发送表情包的概率"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"max_reg_num",children:"最大表情包数量"}),e.jsx(ie,{id:"max_reg_num",type:"number",min:"1",max:"200",value:n.max_reg_num,onChange:c=>i({...n,max_reg_num:Number(c.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(b,{htmlFor:"do_replace",children:"达到最大数量时替换"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"开启后会删除旧表情包,关闭则不再收集新表情包"})]}),e.jsx(Qe,{id:"do_replace",checked:n.do_replace,onCheckedChange:c=>i({...n,do_replace:c})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(ie,{id:"check_interval",type:"number",min:"1",max:"120",value:n.check_interval,onChange:c=>i({...n,check_interval:Number(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"检查表情包注册、破损、删除的时间间隔"})]}),e.jsx(jr,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"steal_emoji",children:"偷取表情包"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人将一些表情包据为己有"})]}),e.jsx(Qe,{id:"steal_emoji",checked:n.steal_emoji,onCheckedChange:c=>i({...n,steal_emoji:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"content_filtration",children:"启用表情包过滤"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只保存符合要求的表情包"})]}),e.jsx(Qe,{id:"content_filtration",checked:n.content_filtration,onCheckedChange:c=>i({...n,content_filtration:c})})]}),n.content_filtration&&e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(ie,{id:"filtration_prompt",placeholder:"例如:符合公序良俗",value:n.filtration_prompt,onChange:c=>i({...n,filtration_prompt:c.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"描述表情包应该符合的要求"})]})]})}function h0({config:n,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(b,{htmlFor:"enable_tool",children:"启用工具系统"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人使用各种工具增强功能"})]}),e.jsx(Qe,{id:"enable_tool",checked:n.enable_tool,onCheckedChange:c=>i({...n,enable_tool:c})})]}),e.jsx(jr,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"enable_mood",children:"启用情绪系统"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"让机器人具有情绪变化能力"})]}),e.jsx(Qe,{id:"enable_mood",checked:n.enable_mood,onCheckedChange:c=>i({...n,enable_mood:c})})]}),n.enable_mood&&e.jsxs("div",{className:"ml-6 space-y-6 border-l-2 border-primary/20 pl-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"mood_update_threshold",children:"情绪更新阈值"}),e.jsx(ie,{id:"mood_update_threshold",type:"number",min:"0.1",max:"10",step:"0.1",value:n.mood_update_threshold||1,onChange:c=>i({...n,mood_update_threshold:Number(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"值越高,情绪更新越慢"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"emotion_style",children:"情感特征"}),e.jsx(Bs,{id:"emotion_style",placeholder:"描述情绪的变化情况,例如:情绪较为稳定,但遭遇特定事件时起伏较大",value:n.emotion_style||"",onChange:c=>i({...n,emotion_style:c.target.value}),rows:2}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"影响机器人的情绪变化方式"})]})]}),e.jsx(jr,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{htmlFor:"all_global",children:"启用全局黑话模式"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人学习和使用群组黑话"})]}),e.jsx(Qe,{id:"all_global",checked:n.all_global,onCheckedChange:c=>i({...n,all_global:c})})]})]})}function x0({config:n,onChange:i}){const[c,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(Xc,{className:"h-3 w-3"})]})]})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{htmlFor:"siliconflow_api_key",children:"SiliconFlow API Key *"}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{id:"siliconflow_api_key",type:c?"text":"password",placeholder:"sk-...",value:n.api_key,onChange:h=>i({api_key:h.target.value}),className:"font-mono pr-10"}),e.jsx(N,{type:"button",variant:"ghost",size:"sm",className:"absolute right-0 top-0 h-full px-3 hover:bg-transparent",onClick:()=>d(!c),children:c?e.jsx(xr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Dt,{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 f0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取Bot配置失败");const c=(await n.json()).config.bot||{};return{qq_account:c.qq_account||0,nickname:c.nickname||"",alias_names:c.alias_names||[]}}async function p0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取人格配置失败");const c=(await n.json()).config.personality||{};return{personality:c.personality||"",reply_style:c.reply_style||"",interest:c.interest||"",plan_style:c.plan_style||"",private_plan_style:c.private_plan_style||""}}async function g0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取表情包配置失败");const c=(await n.json()).config.emoji||{};return{emoji_chance:c.emoji_chance??.4,max_reg_num:c.max_reg_num??40,do_replace:c.do_replace??!0,check_interval:c.check_interval??10,steal_emoji:c.steal_emoji??!0,content_filtration:c.content_filtration??!1,filtration_prompt:c.filtration_prompt||""}}async function j0(){const n=await Te("/api/webui/config/bot",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取其他配置失败");const c=(await n.json()).config,d=c.tool||{},h=c.mood||{},f=c.jargon||{};return{enable_tool:d.enable_tool??!0,enable_mood:h.enable_mood??!1,mood_update_threshold:h.mood_update_threshold,emotion_style:h.emotion_style,all_global:f.all_global??!0}}async function v0(){const n=await Te("/api/webui/config/model",{method:"GET",headers:Ls()});if(!n.ok)throw new Error("读取模型配置失败");return{api_key:((await n.json()).config.api_providers||[]).find(f=>f.name==="SiliconFlow")?.api_key||""}}async function N0(n){const i=await Te("/api/webui/config/bot/section/bot",{method:"POST",headers:Ls(),body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"保存Bot基础配置失败")}return await i.json()}async function b0(n){const i=await Te("/api/webui/config/bot/section/personality",{method:"POST",headers:Ls(),body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"保存人格配置失败")}return await i.json()}async function y0(n){const i=await Te("/api/webui/config/bot/section/emoji",{method:"POST",headers:Ls(),body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"保存表情包配置失败")}return await i.json()}async function w0(n){const i=[];i.push(Te("/api/webui/config/bot/section/tool",{method:"POST",headers:Ls(),body:JSON.stringify({enable_tool:n.enable_tool})})),i.push(Te("/api/webui/config/bot/section/jargon",{method:"POST",headers:Ls(),body:JSON.stringify({all_global:n.all_global})}));const c={enable_mood:n.enable_mood};n.enable_mood&&(c.mood_update_threshold=n.mood_update_threshold||1,c.emotion_style=n.emotion_style||""),i.push(Te("/api/webui/config/bot/section/mood",{method:"POST",headers:Ls(),body:JSON.stringify(c)}));const d=await Promise.all(i);for(const h of d)if(!h.ok){const f=await h.json();throw new Error(f.detail||"保存其他配置失败")}return{success:!0}}async function _0(n){const i=await Te("/api/webui/config/model",{method:"GET",headers:Ls()});if(!i.ok)throw new Error("读取模型配置失败");const d=(await i.json()).config,h=d.api_providers||[],f=h.findIndex(p=>p.name==="SiliconFlow");f>=0?h[f]={...h[f],api_key:n.api_key}:h.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 x={...d,api_providers:h},j=await Te("/api/webui/config/model",{method:"POST",headers:Ls(),body:JSON.stringify(x)});if(!j.ok){const p=await j.json();throw new Error(p.detail||"保存模型配置失败")}return await j.json()}async function rp(){const n=localStorage.getItem("access-token"),i=await Te("/api/webui/setup/complete",{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(!i.ok){const c=await i.json();throw new Error(c.message||"标记配置完成失败")}return await i.json()}async function lo(){const n=await Te("/api/webui/system/restart",{method:"POST",headers:Ls()});if(!n.ok){const i=await n.json();throw new Error(i.detail||"重启失败")}return await n.json()}async function S0(){const n=await Te("/api/webui/system/status",{method:"GET",headers:Ls()});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取状态失败")}return await n.json()}function C0(){const n=ja(),{toast:i}=Vs(),[c,d]=u.useState(0),[h,f]=u.useState(!1),[x,j]=u.useState(!1),[p,w]=u.useState(!0),[v,y]=u.useState({qq_account:0,nickname:"",alias_names:[]}),[S,k]=u.useState({personality:"是一个女大学生,现在在读大二,会刷贴吧。",reply_style:"请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。",interest:"对技术相关话题,游戏和动漫相关话题感兴趣,也对日常话题感兴趣,不喜欢太过沉重严肃的话题",plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 2.如果相同的内容已经被执行,请不要重复执行 3.请控制你的发言频率,不要太过频繁的发言 4.如果有人对你感到厌烦,请减少回复 5.如果有人对你进行攻击,或者情绪激动,请你以合适的方法应对`,private_plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 2.如果相同的内容已经被执行,请不要重复执行 -3.某句话如果已经被回复过,不要重复回复`}),[M,F]=u.useState({emoji_chance:.4,max_reg_num:40,do_replace:!0,check_interval:10,steal_emoji:!0,content_filtration:!1,filtration_prompt:"符合公序良俗"}),[U,O]=u.useState({enable_tool:!0,enable_mood:!1,mood_update_threshold:1,emotion_style:"情绪较为稳定,但遇遇特定事件的时候起伏较大",all_global:!0}),[K,H]=u.useState({api_key:""}),[A,V]=u.useState(!1),[Q,T]=u.useState(""),D=[{id:"bot-basic",title:"Bot基础",description:"配置机器人的基本信息",icon:cr},{id:"personality",title:"人格配置",description:"定义机器人的性格和说话风格",icon:Wc},{id:"emoji",title:"表情包",description:"配置表情包相关设置",icon:Gu},{id:"other",title:"其他设置",description:"工具、情绪系统等配置",icon:oi},{id:"siliconflow",title:"API配置",description:"配置硅基流动API密钥",icon:cg}],ne=(c+1)/D.length*100;u.useEffect(()=>{(async()=>{try{w(!0);const[X,k,se,_,ue]=await Promise.all([u0(),m0(),h0(),x0(),f0()]);y(X),C(k),F(se),O(_),H(ue)}catch(X){i({title:"加载配置失败",description:X instanceof Error?X.message:"无法加载现有配置,将使用默认值",variant:"destructive"})}finally{w(!1)}})()},[i]);const xe=async()=>{j(!0);try{switch(c){case 0:await p0(v);break;case 1:await g0(S);break;case 2:await j0(M);break;case 3:await v0(U);break;case 4:await N0(K);break}return i({title:"保存成功",description:`${D[c].title}配置已保存`}),!0}catch(z){return i({title:"保存失败",description:z instanceof Error?z.message:"未知错误",variant:"destructive"}),!1}finally{j(!1)}},_e=async()=>{await xe()&&c{c>0&&d(c-1)},ge=async()=>{x(!0),V(!0);try{if(T("正在保存API配置..."),!await xe()){x(!1),V(!1);return}T("正在完成初始化..."),await lp(),T("正在重启麦麦..."),await lo(),i({title:"配置完成",description:"麦麦正在重启以应用新配置..."}),T("等待麦麦重启完成...");const X=60;let k=0,se=!1;for(;ksetTimeout(_,1e3));try{(await b0()).running&&(se=!0,T("重启成功!正在跳转..."))}catch{k++}}if(!se)throw new Error("重启超时,请手动检查麦麦状态");setTimeout(()=>{n({to:"/"})},1e3)}catch(z){V(!1),i({title:"配置失败",description:z instanceof Error?z.message:"未知错误",variant:"destructive"})}finally{x(!1)}},ye=async()=>{try{await lp(),n({to:"/"})}catch(z){i({title:"跳过失败",description:z instanceof Error?z.message:"未知错误",variant:"destructive"})}},be=()=>{switch(c){case 0:return e.jsx(i0,{config:v,onChange:y});case 1:return e.jsx(r0,{config:S,onChange:C});case 2:return e.jsx(c0,{config:M,onChange:F});case 3:return e.jsx(o0,{config:U,onChange:O});case 4:return e.jsx(d0,{config:K,onChange:H});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:[A&&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(kt,{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:Q})]}),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"})]}),p?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(pb,{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:["让我们一起完成 ",Yu," 的初始配置"]})]}),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:["步骤 ",c+1," / ",D.length]}),e.jsxs("span",{className:"font-medium text-primary",children:[Math.round(ne),"%"]})]}),e.jsx(wr,{value:ne,className:"h-2"})]}),e.jsx("div",{className:"mb-6 md:mb-8 flex justify-between",children:D.map((z,X)=>{const k=z.icon;return e.jsxs("div",{className:$("flex flex-1 flex-col items-center gap-1 md:gap-2",Xn({to:"/"}),className:"gap-2 w-full sm:w-auto",children:[e.jsx(ao,{className:"h-4 w-4"}),"返回首页"]}),e.jsxs(N,{size:"lg",variant:"outline",onClick:()=>window.history.back(),className:"gap-2 w-full sm:w-auto",children:[e.jsx(ii,{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 He=eb,qe=sb,Le=u.forwardRef(({className:n,children:i,...c},d)=>e.jsxs($p,{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),...c,children:[i,e.jsx(JN,{asChild:!0,children:e.jsx(Bl,{className:"h-4 w-4 opacity-50"})})]}));Le.displayName=$p.displayName;const Tg=u.forwardRef(({className:n,...i},c)=>e.jsx(Qp,{ref:c,className:$("flex cursor-default items-center justify-center py-1",n),...i,children:e.jsx(pr,{className:"h-4 w-4"})}));Tg.displayName=Qp.displayName;const Eg=u.forwardRef(({className:n,...i},c)=>e.jsx(Yp,{ref:c,className:$("flex cursor-default items-center justify-center py-1",n),...i,children:e.jsx(Bl,{className:"h-4 w-4"})}));Eg.displayName=Yp.displayName;const Ue=u.forwardRef(({className:n,children:i,position:c="popper",...d},h)=>e.jsx(ZN,{children:e.jsxs(Xp,{ref:h,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]",c==="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:c,...d,children:[e.jsx(Tg,{}),e.jsx(IN,{className:$("p-1",c==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:i}),e.jsx(Eg,{})]})}));Ue.displayName=Xp.displayName;const w0=u.forwardRef(({className:n,...i},c)=>e.jsx(Kp,{ref:c,className:$("px-2 py-1.5 text-sm font-semibold",n),...i}));w0.displayName=Kp.displayName;const le=u.forwardRef(({className:n,children:i,...c},d)=>e.jsxs(Jp,{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),...c,children:[e.jsx("span",{className:"absolute right-2 flex h-3.5 w-3.5 items-center justify-center",children:e.jsx(PN,{children:e.jsx(sa,{className:"h-4 w-4"})})}),e.jsx(WN,{children:i})]}));le.displayName=Jp.displayName;const _0=u.forwardRef(({className:n,...i},c)=>e.jsx(Zp,{ref:c,className:$("-mx-1 my-1 h-px bg-muted",n),...i}));_0.displayName=Zp.displayName;const Ua=AN,Ba=MN,_a=u.forwardRef(({className:n,align:i="center",sideOffset:c=4,...d},h)=>e.jsx(zN,{children:e.jsx(Rp,{ref:h,align:i,sideOffset:c,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})}));_a.displayName=Rp.displayName;const ql="/api/webui/config";async function np(){const i=await(await Te(`${ql}/bot`)).json();if(!i.success)throw new Error("获取配置数据失败");return i.config}async function ni(){const i=await(await Te(`${ql}/model`)).json();if(!i.success)throw new Error("获取模型配置数据失败");return i.config}async function ip(n){const c=await(await Te(`${ql}/bot`,{method:"POST",body:JSON.stringify(n)})).json();if(!c.success)throw new Error(c.message||"保存配置失败")}async function S0(){const i=await(await Te(`${ql}/bot/raw`)).json();if(!i.success)throw new Error("获取配置源代码失败");return i.content}async function C0(n){const c=await(await Te(`${ql}/bot/raw`,{method:"POST",body:JSON.stringify({raw_content:n})})).json();if(!c.success)throw new Error(c.message||"保存配置失败")}async function to(n){const c=await(await Te(`${ql}/model`,{method:"POST",body:JSON.stringify(n)})).json();if(!c.success)throw new Error(c.message||"保存配置失败")}async function k0(n,i){const d=await(await Te(`${ql}/bot/section/${n}`,{method:"POST",body:JSON.stringify(i)})).json();if(!d.success)throw new Error(d.message||`保存配置节 ${n} 失败`)}async function Uu(n,i){const d=await(await Te(`${ql}/model/section/${n}`,{method:"POST",body:JSON.stringify(i)})).json();if(!d.success)throw new Error(d.message||`保存配置节 ${n} 失败`)}async function T0(n,i="openai",c="/models"){const d=new URLSearchParams({provider_name:n,parser:i,endpoint:c}),h=await Te(`/api/webui/models/list?${d}`);if(!h.ok){const f=await h.json().catch(()=>({}));throw new Error(f.detail||`获取模型列表失败 (${h.status})`)}const x=await h.json();if(!x.success)throw new Error("获取模型列表失败");return x.models}async function E0(n){const i=new URLSearchParams({provider_name:n}),c=await Te(`/api/webui/models/test-connection-by-name?${i}`,{method:"POST"});if(!c.ok){const d=await c.json().catch(()=>({}));throw new Error(d.detail||`测试连接失败 (${c.status})`)}return await c.json()}const z0=ci("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"}}),cl=u.forwardRef(({className:n,variant:i,...c},d)=>e.jsx("div",{ref:d,role:"alert",className:$(z0({variant:i}),n),...c}));cl.displayName="Alert";const A0=u.forwardRef(({className:n,...i},c)=>e.jsx("h5",{ref:c,className:$("mb-1 font-medium leading-none tracking-tight",n),...i}));A0.displayName="AlertTitle";const ol=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:$("text-sm [&_p]:leading-relaxed",n),...i}));ol.displayName="AlertDescription";function Ju({onRestartComplete:n,onRestartFailed:i}){const[c,d]=u.useState(0),[h,x]=u.useState("restarting"),[f,j]=u.useState(0),[p,w]=u.useState(0);u.useEffect(()=>{const S=setInterval(()=>{d(F=>F>=90?F:F+1)},200),C=setInterval(()=>{j(F=>F+1)},1e3),M=setTimeout(()=>{x("checking"),v()},3e3);return()=>{clearInterval(S),clearInterval(C),clearTimeout(M)}},[]);const v=()=>{const C=async()=>{try{if(w(F=>F+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{p<60?setTimeout(C,2e3):(x("failed"),i?.())}};C()},y=S=>{const C=Math.floor(S/60),M=S%60;return`${C}:${M.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:[h==="restarting"&&e.jsxs(e.Fragment,{children:[e.jsx(kt,{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:"请稍候,麦麦正在重启中..."})]}),h==="checking"&&e.jsxs(e.Fragment,{children:[e.jsx(kt,{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:["等待服务恢复... (尝试 ",p,"/60)"]})]}),h==="success"&&e.jsxs(e.Fragment,{children:[e.jsx(fa,{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:"正在跳转到登录页面..."})]}),h==="failed"&&e.jsxs(e.Fragment,{children:[e.jsx(Oa,{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:"服务未能在预期时间内恢复,请手动检查或刷新页面"})]})]}),h!=="failed"&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(wr,{value:c,className:"h-2"}),e.jsxs("div",{className:"flex justify-between text-sm text-muted-foreground",children:[e.jsxs("span",{children:[c,"%"]}),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:[h==="restarting"&&"🔄 配置已保存,正在重启主程序...",h==="checking"&&"⏳ 正在等待服务恢复,请勿关闭页面...",h==="success"&&"✅ 配置已生效,服务运行正常",h==="failed"&&"⚠️ 如果长时间无响应,请尝试手动重启"]})}),h==="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"),w(0),v()},className:"flex-1 px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/90",children:"重试检测"})]})]})})}const M0={name:"toml",startState:function(){return{inString:!1,stringType:"",lhs:!0,inArray:0}},token:function(n,i){let c;if(!i.inString&&(c=n.match(/^('''|"""|'|")/))&&(i.stringType=c[0],i.inString=!0),n.sol()&&!i.inString&&i.inArray===0&&(i.lhs=!0),i.inString){for(;i.inString;)if(n.match(i.stringType))i.inString=!1;else if(n.peek()==="\\")n.next(),n.next();else{if(n.eol())break;n.match(/^.[^\\\"\']*/)}return i.lhs?"property":"string"}else{if(i.inArray&&n.peek()==="]")return n.next(),i.inArray--,"bracket";if(i.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(i.lhs&&n.eatWhile(function(d){return d!="="&&d!=" "}))return"property";if(i.lhs&&n.peek()==="=")return n.next(),i.lhs=!1,null;if(!i.lhs&&n.match(/^\d\d\d\d[\d\-\:\.T]*Z/))return"atom";if(!i.lhs&&(n.match("true")||n.match("false")))return"atom";if(!i.lhs&&n.peek()==="[")return i.inArray++,n.next(),"bracket";if(!i.lhs&&n.match(/^\-?\d+(?:\.\d+)?/))return"number";n.eatSpace()||n.next()}return null},languageData:{commentTokens:{line:"#"}}},D0={python:[Gb()],json:[Vb(),Fb()],toml:[qb.define(M0)],text:[]};function O0({value:n,onChange:i,language:c="text",readOnly:d=!1,height:h="400px",minHeight:x,maxHeight:f,placeholder:j,theme:p="dark",className:w=""}){const[v,y]=u.useState(!1);if(u.useEffect(()=>{y(!0)},[]),!v)return e.jsx("div",{className:`rounded-md border bg-muted animate-pulse ${w}`,style:{height:h,minHeight:x,maxHeight:f}});const S=[...D0[c]||[],Kf.lineWrapping];return d&&S.push(Kf.editable.of(!1)),e.jsx("div",{className:`rounded-md overflow-hidden border ${w}`,children:e.jsx($b,{value:n,height:h,minHeight:x,maxHeight:f,theme:p==="dark"?Qb:void 0,extensions:S,onChange:i,placeholder:j,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 R0(){const[n,i]=u.useState(!0),[c,d]=u.useState(!1),[h,x]=u.useState(!1),[f,j]=u.useState(!1),[p,w]=u.useState(!1),[v,y]=u.useState(!1),[S,C]=u.useState("visual"),[M,F]=u.useState(""),[U,O]=u.useState(!1),{toast:K}=Gs(),[H,A]=u.useState(null),[V,Q]=u.useState(null),[T,D]=u.useState(null),[ne,xe]=u.useState(null),[_e,Se]=u.useState(null),[ge,ye]=u.useState(null),[be,z]=u.useState(null),[X,k]=u.useState(null),[se,_]=u.useState(null),[ue,ie]=u.useState(null),[ae,fe]=u.useState(null),[Ne,me]=u.useState(null),[G,P]=u.useState(null),[B,W]=u.useState(null),[Ce,Me]=u.useState(null),[re,De]=u.useState(null),[Vs,Qs]=u.useState(null),[de,Ee]=u.useState(null),ts=u.useRef(null),Ke=u.useRef(!0),lt=u.useRef({}),Ot=u.useCallback(async()=>{try{const ke=await S0();F(ke),O(!1)}catch(ke){K({variant:"destructive",title:"加载失败",description:ke instanceof Error?ke.message:"加载源代码失败"})}},[K]),bt=u.useCallback(async()=>{try{i(!0);const ke=await np();lt.current=ke,A(ke.bot),Q(ke.personality);const ve=ke.chat;ve.talk_value_rules||(ve.talk_value_rules=[]),D(ve),xe(ke.expression),Se(ke.emoji),ye(ke.memory),z(ke.tool),k(ke.mood),_(ke.voice),ie(ke.lpmm_knowledge),fe(ke.keyword_reaction),me(ke.response_post_process),P(ke.chinese_typo),W(ke.response_splitter),Me(ke.log),De(ke.debug),Qs(ke.maim_message),Ee(ke.telemetry),j(!1),Ke.current=!1,await Ot()}catch(ke){console.error("加载配置失败:",ke),K({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}finally{i(!1)}},[K,Ot]);u.useEffect(()=>{bt()},[bt]);const Pe=u.useCallback(async(ke,ve)=>{if(!Ke.current)try{x(!0),await k0(ke,ve),j(!1)}catch(ns){console.error(`自动保存 ${ke} 失败:`,ns),j(!0)}finally{x(!1)}},[]),R=u.useCallback((ke,ve)=>{Ke.current||(j(!0),ts.current&&clearTimeout(ts.current),ts.current=setTimeout(()=>{Pe(ke,ve)},2e3))},[Pe]);u.useEffect(()=>{H&&!Ke.current&&R("bot",H)},[H,R]),u.useEffect(()=>{V&&!Ke.current&&R("personality",V)},[V,R]),u.useEffect(()=>{T&&!Ke.current&&R("chat",T)},[T,R]),u.useEffect(()=>{ne&&!Ke.current&&R("expression",ne)},[ne,R]),u.useEffect(()=>{_e&&!Ke.current&&R("emoji",_e)},[_e,R]),u.useEffect(()=>{ge&&!Ke.current&&R("memory",ge)},[ge,R]),u.useEffect(()=>{be&&!Ke.current&&R("tool",be)},[be,R]),u.useEffect(()=>{X&&!Ke.current&&R("mood",X)},[X,R]),u.useEffect(()=>{se&&!Ke.current&&R("voice",se)},[se,R]),u.useEffect(()=>{ue&&!Ke.current&&R("lpmm_knowledge",ue)},[ue,R]),u.useEffect(()=>{ae&&!Ke.current&&R("keyword_reaction",ae)},[ae,R]),u.useEffect(()=>{Ne&&!Ke.current&&R("response_post_process",Ne)},[Ne,R]),u.useEffect(()=>{G&&!Ke.current&&R("chinese_typo",G)},[G,R]),u.useEffect(()=>{B&&!Ke.current&&R("response_splitter",B)},[B,R]),u.useEffect(()=>{Ce&&!Ke.current&&R("log",Ce)},[Ce,R]),u.useEffect(()=>{re&&!Ke.current&&R("debug",re)},[re,R]),u.useEffect(()=>{Vs&&!Ke.current&&R("maim_message",Vs)},[Vs,R]),u.useEffect(()=>{de&&!Ke.current&&R("telemetry",de)},[de,R]);const Re=async()=>{try{d(!0),await C0(M),j(!1),O(!1),K({title:"保存成功",description:"配置已保存"}),await bt()}catch(ke){O(!0),K({variant:"destructive",title:"保存失败",description:ke instanceof Error?ke.message:"保存配置失败"})}finally{d(!1)}},ze=async ke=>{if(f){K({variant:"destructive",title:"切换失败",description:"请先保存当前更改"});return}if(C(ke),ke==="source")await Ot();else try{const ve=await np();lt.current=ve,A(ve.bot),Q(ve.personality);const ns=ve.chat;ns.talk_value_rules||(ns.talk_value_rules=[]),D(ns),xe(ve.expression),Se(ve.emoji),ye(ve.memory),z(ve.tool),k(ve.mood),_(ve.voice),ie(ve.lpmm_knowledge),fe(ve.keyword_reaction),me(ve.response_post_process),P(ve.chinese_typo),W(ve.response_splitter),Me(ve.log),De(ve.debug),Qs(ve.maim_message),Ee(ve.telemetry),j(!1)}catch(ve){console.error("加载配置失败:",ve),K({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}},$e=async()=>{try{d(!0),ts.current&&clearTimeout(ts.current);const ke={...lt.current,bot:H,personality:V,chat:T,expression:ne,emoji:_e,memory:ge,tool:be,mood:X,voice:se,lpmm_knowledge:ue,keyword_reaction:ae,response_post_process:Ne,chinese_typo:G,response_splitter:B,log:Ce,debug:re,maim_message:Vs,telemetry:de};await ip(ke),j(!1),K({title:"保存成功",description:"麦麦主程序配置已保存"})}catch(ke){console.error("保存配置失败:",ke),K({title:"保存失败",description:ke.message,variant:"destructive"})}finally{d(!1)}},Es=async()=>{try{w(!0),lo().catch(()=>{}),y(!0)}catch(ke){console.error("重启失败:",ke),y(!1),K({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),w(!1)}},We=async()=>{try{d(!0),ts.current&&clearTimeout(ts.current);const ke={...lt.current,bot:H,personality:V,chat:T,expression:ne,emoji:_e,memory:ge,tool:be,mood:X,voice:se,lpmm_knowledge:ue,keyword_reaction:ae,response_post_process:Ne,chinese_typo:G,response_splitter:B,log:Ce,debug:re,maim_message:Vs,telemetry:de};await ip(ke),j(!1),K({title:"保存成功",description:"配置已保存,即将重启麦麦..."}),await new Promise(ve=>setTimeout(ve,500)),await Es()}catch(ke){console.error("保存失败:",ke),K({title:"保存失败",description:ke.message,variant:"destructive"})}finally{d(!1)}},nt=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},vs=()=>{y(!1),w(!1),K({title:"重启失败",description:"服务器未能在预期时间内恢复,请手动检查",variant:"destructive"})};return n?e.jsx(ss,{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(ss,{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(N,{onClick:S==="visual"?$e:Re,disabled:c||h||!f||p,size:"sm",variant:"outline",className:"w-20 sm:w-24",children:[e.jsx(yr,{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:c?"保存中":h?"自动":f?"保存":"已保存"})]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{disabled:c||h||p,size:"sm",className:"w-20 sm:w-28",children:[e.jsx(br,{className:"h-4 w-4 flex-shrink-0"}),e.jsx("span",{className:"ml-1 truncate text-xs sm:text-sm",children:p?"重启中":f?"保存重启":"重启"})]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认重启麦麦?"}),e.jsx(ds,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:f?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:f?We:Es,children:f?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsx("div",{className:"flex",children:e.jsx(La,{value:S,onValueChange:ke=>ze(ke),className:"w-full",children:e.jsxs(wa,{className:"h-8 sm:h-9 w-full grid grid-cols-2",children:[e.jsxs(fs,{value:"visual",className:"text-xs sm:text-sm",children:[e.jsx(vb,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"可视化编辑"]}),e.jsxs(fs,{value:"source",className:"text-xs sm:text-sm",children:[e.jsx(Nb,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"源代码编辑"]})]})})})]}),e.jsxs(cl,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ol,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),S==="source"&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs(cl,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ol,{children:[e.jsx("strong",{children:"源代码模式(高级功能):"}),"直接编辑 TOML 配置文件。此功能仅适用于熟悉 TOML 语法的高级用户。保存时会在后端验证格式,只有格式完全正确才能保存。",U&&e.jsx("span",{className:"text-destructive font-semibold ml-2",children:"⚠️ 上次保存失败,请检查 TOML 格式"})]})]}),e.jsx(O0,{value:M,onChange:ke=>{F(ke),j(!0),U&&O(!1)},language:"toml",theme:"dark",height:"calc(100vh - 280px)",minHeight:"500px",placeholder:"TOML 配置内容"})]}),S==="visual"&&e.jsx(e.Fragment,{children:e.jsxs(La,{defaultValue:"bot",className:"w-full",children:[e.jsxs(wa,{className:"flex flex-wrap h-auto gap-1 p-1 sm:grid sm:grid-cols-5 lg:grid-cols-10",children:[e.jsx(fs,{value:"bot",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"基本信息"}),e.jsx(fs,{value:"personality",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"人格"}),e.jsx(fs,{value:"chat",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"聊天"}),e.jsx(fs,{value:"expression",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"表达"}),e.jsx(fs,{value:"features",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"功能"}),e.jsx(fs,{value:"processing",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"处理"}),e.jsx(fs,{value:"mood",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"情绪"}),e.jsx(fs,{value:"voice",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"语音"}),e.jsx(fs,{value:"lpmm",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"知识库"}),e.jsx(fs,{value:"other",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"其他"})]}),e.jsx(Ms,{value:"bot",className:"space-y-4",children:H&&e.jsx(L0,{config:H,onChange:A})}),e.jsx(Ms,{value:"personality",className:"space-y-4",children:V&&e.jsx(U0,{config:V,onChange:Q})}),e.jsx(Ms,{value:"chat",className:"space-y-4",children:T&&e.jsx(B0,{config:T,onChange:D})}),e.jsx(Ms,{value:"expression",className:"space-y-4",children:ne&&e.jsx(q0,{config:ne,onChange:xe})}),e.jsx(Ms,{value:"features",className:"space-y-4",children:_e&&ge&&be&&e.jsx(G0,{emojiConfig:_e,memoryConfig:ge,toolConfig:be,onEmojiChange:Se,onMemoryChange:ye,onToolChange:z})}),e.jsx(Ms,{value:"processing",className:"space-y-4",children:ae&&Ne&&G&&B&&e.jsx(V0,{keywordReactionConfig:ae,responsePostProcessConfig:Ne,chineseTypoConfig:G,responseSplitterConfig:B,onKeywordReactionChange:fe,onResponsePostProcessChange:me,onChineseTypoChange:P,onResponseSplitterChange:W})}),e.jsx(Ms,{value:"mood",className:"space-y-4",children:X&&e.jsx(F0,{config:X,onChange:k})}),e.jsx(Ms,{value:"voice",className:"space-y-4",children:se&&e.jsx($0,{config:se,onChange:_})}),e.jsx(Ms,{value:"lpmm",className:"space-y-4",children:ue&&e.jsx(Q0,{config:ue,onChange:ie})}),e.jsxs(Ms,{value:"other",className:"space-y-4",children:[Ce&&e.jsx(Y0,{config:Ce,onChange:Me}),re&&e.jsx(X0,{config:re,onChange:De}),Vs&&e.jsx(K0,{config:Vs,onChange:Qs}),de&&e.jsx(J0,{config:de,onChange:Ee})]})]})}),v&&e.jsx(Ju,{onRestartComplete:nt,onRestartFailed:vs})]})})}function L0({config:n,onChange:i}){const c=()=>{i({...n,platforms:[...n.platforms,""]})},d=p=>{i({...n,platforms:n.platforms.filter((w,v)=>v!==p)})},h=(p,w)=>{const v=[...n.platforms];v[p]=w,i({...n,platforms:v})},x=()=>{i({...n,alias_names:[...n.alias_names,""]})},f=p=>{i({...n,alias_names:n.alias_names.filter((w,v)=>v!==p)})},j=(p,w)=>{const v=[...n.alias_names];v[p]=w,i({...n,alias_names:v})};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(b,{htmlFor:"platform",children:"平台"}),e.jsx(oe,{id:"platform",value:n.platform,onChange:p=>i({...n,platform:p.target.value}),placeholder:"qq"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"qq_account",children:"QQ账号"}),e.jsx(oe,{id:"qq_account",value:n.qq_account,onChange:p=>i({...n,qq_account:p.target.value}),placeholder:"123456789"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"nickname",children:"昵称"}),e.jsx(oe,{id:"nickname",value:n.nickname,onChange:p=>i({...n,nickname:p.target.value}),placeholder:"麦麦"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{children:"其他平台账号"}),e.jsxs(N,{onClick:c,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[n.platforms.map((p,w)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(oe,{value:p,onChange:v=>h(w,v.target.value),placeholder:"wx:114514"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除平台账号 "',p||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>d(w),children:"删除"})]})]})]})]},w)),n.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(b,{children:"别名"}),e.jsxs(N,{onClick:x,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[n.alias_names.map((p,w)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(oe,{value:p,onChange:v=>j(w,v.target.value),placeholder:"小麦"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除别名 "',p||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>f(w),children:"删除"})]})]})]})]},w)),n.alias_names.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无别名"})]})]})]})]})})}function U0({config:n,onChange:i}){const c=()=>{i({...n,states:[...n.states,""]})},d=x=>{i({...n,states:n.states.filter((f,j)=>j!==x)})},h=(x,f)=>{const j=[...n.states];j[x]=f,i({...n,states:j})};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(b,{htmlFor:"personality",children:"人格特质"}),e.jsx(Fs,{id:"personality",value:n.personality,onChange:x=>i({...n,personality:x.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(b,{htmlFor:"reply_style",children:"表达风格"}),e.jsx(Fs,{id:"reply_style",value:n.reply_style,onChange:x=>i({...n,reply_style:x.target.value}),placeholder:"描述说话的表达风格和习惯",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"interest",children:"兴趣"}),e.jsx(Fs,{id:"interest",value:n.interest,onChange:x=>i({...n,interest:x.target.value}),placeholder:"会影响麦麦对什么话题进行回复",rows:2})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"plan_style",children:"说话规则与行为风格"}),e.jsx(Fs,{id:"plan_style",value:n.plan_style,onChange:x=>i({...n,plan_style:x.target.value}),placeholder:"麦麦的说话规则和行为风格",rows:5})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"visual_style",children:"识图规则"}),e.jsx(Fs,{id:"visual_style",value:n.visual_style,onChange:x=>i({...n,visual_style:x.target.value}),placeholder:"识图时的处理规则",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"private_plan_style",children:"私聊规则"}),e.jsx(Fs,{id:"private_plan_style",value:n.private_plan_style,onChange:x=>i({...n,private_plan_style:x.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(b,{children:"状态列表(人格多样性)"}),e.jsxs(N,{onClick:c,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加状态"]})]}),e.jsx("div",{className:"space-y-2",children:n.states.map((x,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Fs,{value:x,onChange:j=>h(f,j.target.value),placeholder:"描述一个人格状态",rows:2}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsx(ds,{children:"确定要删除这个人格状态吗?此操作无法撤销。"})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>d(f),children:"删除"})]})]})]})]},f))})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"state_probability",children:"状态替换概率"}),e.jsx(oe,{id:"state_probability",type:"number",step:"0.1",min:"0",max:"1",value:n.state_probability,onChange:x=>i({...n,state_probability:parseFloat(x.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"每次构建人格时替换 personality 的概率(0.0-1.0)"})]})]})]})})}function B0({config:n,onChange:i}){const c=()=>{i({...n,talk_value_rules:[...n.talk_value_rules,{target:"",time:"00:00-23:59",value:1}]})},d=j=>{i({...n,talk_value_rules:n.talk_value_rules.filter((p,w)=>w!==j)})},h=(j,p,w)=>{const v=[...n.talk_value_rules];v[j]={...v[j],[p]:w},i({...n,talk_value_rules:v})},x=({value:j,onChange:p})=>{const[w,v]=u.useState("00"),[y,S]=u.useState("00"),[C,M]=u.useState("23"),[F,U]=u.useState("59");u.useEffect(()=>{const K=j.split("-");if(K.length===2){const[H,A]=K,[V,Q]=H.split(":"),[T,D]=A.split(":");V&&v(V.padStart(2,"0")),Q&&S(Q.padStart(2,"0")),T&&M(T.padStart(2,"0")),D&&U(D.padStart(2,"0"))}},[j]);const O=(K,H,A,V)=>{const Q=`${K}:${H}-${A}:${V}`;p(Q)};return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",className:"w-full justify-start font-mono text-sm",children:[e.jsx(li,{className:"h-4 w-4 mr-2"}),j||"选择时间段"]})}),e.jsx(_a,{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(b,{className:"text-xs",children:"小时"}),e.jsxs(He,{value:w,onValueChange:K=>{v(K),O(K,y,C,F)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:Array.from({length:24},(K,H)=>H).map(K=>e.jsx(le,{value:K.toString().padStart(2,"0"),children:K.toString().padStart(2,"0")},K))})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs",children:"分钟"}),e.jsxs(He,{value:y,onValueChange:K=>{S(K),O(w,K,C,F)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:Array.from({length:60},(K,H)=>H).map(K=>e.jsx(le,{value:K.toString().padStart(2,"0"),children:K.toString().padStart(2,"0")},K))})]})]})]})]}),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(b,{className:"text-xs",children:"小时"}),e.jsxs(He,{value:C,onValueChange:K=>{M(K),O(w,y,K,F)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:Array.from({length:24},(K,H)=>H).map(K=>e.jsx(le,{value:K.toString().padStart(2,"0"),children:K.toString().padStart(2,"0")},K))})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs",children:"分钟"}),e.jsxs(He,{value:F,onValueChange:K=>{U(K),O(w,y,C,K)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:Array.from({length:60},(K,H)=>H).map(K=>e.jsx(le,{value:K.toString().padStart(2,"0"),children:K.toString().padStart(2,"0")},K))})]})]})]})]})]})})]})},f=({rule:j})=>{const p=`{ target = "${j.target}", time = "${j.time}", value = ${j.value.toFixed(1)} }`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(_a,{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:p}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})};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(b,{htmlFor:"talk_value",children:"聊天频率(基础值)"}),e.jsx(oe,{id:"talk_value",type:"number",step:"0.1",min:"0",max:"1",value:n.talk_value,onChange:j=>i({...n,talk_value:parseFloat(j.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(Xe,{id:"mentioned_bot_reply",checked:n.mentioned_bot_reply,onCheckedChange:j=>i({...n,mentioned_bot_reply:j})}),e.jsx(b,{htmlFor:"mentioned_bot_reply",className:"cursor-pointer",children:"启用提及必回复"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"max_context_size",children:"上下文长度"}),e.jsx(oe,{id:"max_context_size",type:"number",min:"1",value:n.max_context_size,onChange:j=>i({...n,max_context_size:parseInt(j.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"planner_smooth",children:"规划器平滑"}),e.jsx(oe,{id:"planner_smooth",type:"number",step:"1",min:"0",value:n.planner_smooth,onChange:j=>i({...n,planner_smooth:parseFloat(j.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(Xe,{id:"enable_talk_value_rules",checked:n.enable_talk_value_rules,onCheckedChange:j=>i({...n,enable_talk_value_rules:j})}),e.jsx(b,{htmlFor:"enable_talk_value_rules",className:"cursor-pointer",children:"启用动态发言频率规则"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Xe,{id:"include_planner_reasoning",checked:n.include_planner_reasoning,onCheckedChange:j=>i({...n,include_planner_reasoning:j})}),e.jsx(b,{htmlFor:"include_planner_reasoning",className:"cursor-pointer",children:"将 planner 推理加入 replyer"})]})]})]}),n.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(N,{onClick:c,size:"sm",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),n.talk_value_rules&&n.talk_value_rules.length>0?e.jsx("div",{className:"space-y-4",children:n.talk_value_rules.map((j,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(f,{rule:j}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{variant:"ghost",size:"sm",children:e.jsx(ls,{className:"h-4 w-4 text-destructive"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除规则 #",p+1," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>d(p),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(He,{value:j.target===""?"global":"specific",onValueChange:w=>{w==="global"?h(p,"target",""):h(p,"target","qq::group")},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"global",children:"全局配置"}),e.jsx(le,{value:"specific",children:"详细配置"})]})]})]}),j.target!==""&&(()=>{const w=j.target.split(":"),v=w[0]||"qq",y=w[1]||"",S=w[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(b,{className:"text-xs font-medium",children:"平台"}),e.jsxs(He,{value:v,onValueChange:C=>{h(p,"target",`${C}:${y}:${S}`)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(oe,{value:y,onChange:C=>{h(p,"target",`${v}:${C.target.value}:${S}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"类型"}),e.jsxs(He,{value:S,onValueChange:C=>{h(p,"target",`${v}:${y}:${C}`)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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:",j.target||"(未设置)"]})]})})(),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"时间段 (Time)"}),e.jsx(x,{value:j.time,onChange:w=>h(p,"time",w)}),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(b,{htmlFor:`rule-value-${p}`,className:"text-xs font-medium",children:"发言频率值 (Value)"}),e.jsx(oe,{id:`rule-value-${p}`,type:"number",step:"0.01",min:"0.01",max:"1",value:j.value,onChange:w=>{const v=parseFloat(w.target.value);isNaN(v)||h(p,"value",Math.max(.01,Math.min(1,v)))},className:"w-20 h-8 text-xs"})]}),e.jsx(Ma,{value:[j.value],onValueChange:w=>h(p,"value",w[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 表示正常发言"]})]})]})]})]})}function H0({member:n,groupIndex:i,memberIndex:c,availableChatIds:d,onUpdate:h,onRemove:x}){const f=d.includes(n)||n==="*",[j,p]=u.useState(!f);return e.jsxs("div",{className:"flex gap-2",children:[e.jsx("div",{className:"flex-1 flex gap-2",children:j?e.jsxs(e.Fragment,{children:[e.jsx(oe,{value:n,onChange:w=>h(i,c,w.target.value),placeholder:'输入 "*" 或 "qq:123456:group"',className:"flex-1"}),d.length>0&&e.jsx(N,{size:"sm",variant:"outline",onClick:()=>p(!1),title:"切换到下拉选择",children:"下拉"})]}):e.jsxs(e.Fragment,{children:[e.jsxs(He,{value:n,onValueChange:w=>h(i,c,w),children:[e.jsx(Le,{className:"flex-1",children:e.jsx(qe,{placeholder:"选择聊天流"})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"*",children:"* (全局共享)"}),d.map((w,v)=>e.jsx(le,{value:w,children:w},v))]})]}),e.jsx(N,{size:"sm",variant:"outline",onClick:()=>p(!0),title:"切换到手动输入",children:"输入"})]})}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除组成员 "',n||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>x(i,c),children:"删除"})]})]})]})]})}function q0({config:n,onChange:i}){const c=()=>{i({...n,learning_list:[...n.learning_list,["","enable","enable","1.0"]]})},d=y=>{i({...n,learning_list:n.learning_list.filter((S,C)=>C!==y)})},h=(y,S,C)=>{const M=[...n.learning_list];M[y][S]=C,i({...n,learning_list:M})},x=({rule:y})=>{const S=`["${y[0]}", "${y[1]}", "${y[2]}", "${y[3]}"]`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(_a,{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=()=>{i({...n,expression_groups:[...n.expression_groups,[]]})},j=y=>{i({...n,expression_groups:n.expression_groups.filter((S,C)=>C!==y)})},p=y=>{const S=[...n.expression_groups];S[y]=[...S[y],""],i({...n,expression_groups:S})},w=(y,S)=>{const C=[...n.expression_groups];C[y]=C[y].filter((M,F)=>F!==S),i({...n,expression_groups:C})},v=(y,S,C)=>{const M=[...n.expression_groups];M[y][S]=C,i({...n,expression_groups:M})};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(N,{onClick:c,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),e.jsxs("div",{className:"space-y-4",children:[n.learning_list.map((y,S)=>{const C=n.learning_list.some((H,A)=>A!==S&&H[0]===""),M=y[0]==="",F=y[0].split(":"),U=F[0]||"qq",O=F[1]||"",K=F[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," ",M&&"(全局配置)"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(x,{rule:y}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除学习规则 ",S+1," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>d(S),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(He,{value:M?"global":"specific",onValueChange:H=>{H==="global"?h(S,0,""):h(S,0,"qq::group")},disabled:C&&!M,children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"global",children:"全局配置"}),e.jsx(le,{value:"specific",disabled:C&&!M,children:"详细配置"})]})]}),C&&!M&&e.jsx("p",{className:"text-xs text-amber-600",children:"已存在全局配置,无法创建新的全局配置"})]}),!M&&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(b,{className:"text-xs font-medium",children:"平台"}),e.jsxs(He,{value:U,onValueChange:H=>{h(S,0,`${H}:${O}:${K}`)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(oe,{value:O,onChange:H=>{h(S,0,`${U}:${H.target.value}:${K}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"类型"}),e.jsxs(He,{value:K,onValueChange:H=>{h(S,0,`${U}:${O}:${H}`)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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:",y[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(b,{className:"text-xs font-medium",children:"使用学到的表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦使用从聊天中学到的表达方式"})]}),e.jsx(Xe,{checked:y[1]==="enable",onCheckedChange:H=>h(S,1,H?"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(b,{className:"text-xs font-medium",children:"学习表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦从聊天中学习新的表达方式"})]}),e.jsx(Xe,{checked:y[2]==="enable",onCheckedChange:H=>h(S,2,H?"enable":"disable")})]})}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{className:"text-xs font-medium",children:"学习强度"}),e.jsx(oe,{type:"number",step:"0.1",min:"0",max:"5",value:y[3],onChange:H=>{const A=parseFloat(H.target.value);isNaN(A)||h(S,3,Math.max(0,Math.min(5,A)).toFixed(1))},className:"w-20 h-8 text-xs"})]}),e.jsx(Ma,{value:[parseFloat(y[3])||1],onValueChange:H=>h(S,3,H[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)}),n.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(Xe,{checked:n.reflect,onCheckedChange:y=>i({...n,reflect:y})})]}),n.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=(n.reflect_operator_id||"").split(":"),C=S[0]||"qq",M=S[1]||"",F=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(b,{className:"text-xs font-medium",children:"平台"}),e.jsxs(He,{value:C,onValueChange:U=>{i({...n,reflect_operator_id:`${U}:${M}:${F}`})},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"用户/群 ID"}),e.jsx(oe,{value:M,onChange:U=>{i({...n,reflect_operator_id:`${C}:${U.target.value}:${F}`})},placeholder:"输入 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"类型"}),e.jsxs(He,{value:F,onValueChange:U=>{i({...n,reflect_operator_id:`${C}:${M}:${U}`})},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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:",n.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(N,{onClick:()=>{i({...n,allow_reflect:[...n.allow_reflect||[],"qq::group"]})},size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加聊天流"]})]}),e.jsxs("div",{className:"space-y-2",children:[(n.allow_reflect||[]).map((y,S)=>{const C=y.split(":"),M=C[0]||"qq",F=C[1]||"",U=C[2]||"group";return e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-muted/50",children:[e.jsxs(He,{value:M,onValueChange:O=>{const K=[...n.allow_reflect];K[S]=`${O}:${F}:${U}`,i({...n,allow_reflect:K})},children:[e.jsx(Le,{className:"w-24",children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]}),e.jsx(oe,{value:F,onChange:O=>{const K=[...n.allow_reflect];K[S]=`${M}:${O.target.value}:${U}`,i({...n,allow_reflect:K})},placeholder:"ID",className:"flex-1 font-mono text-sm"}),e.jsxs(He,{value:U,onValueChange:O=>{const K=[...n.allow_reflect];K[S]=`${M}:${F}:${O}`,i({...n,allow_reflect:K})},children:[e.jsx(Le,{className:"w-32",children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"group",children:"群组"}),e.jsx(le,{value:"private",children:"私聊"})]})]}),e.jsx(N,{onClick:()=>{i({...n,allow_reflect:n.allow_reflect.filter((O,K)=>K!==S)})},size:"sm",variant:"ghost",children:e.jsx(ls,{className:"h-4 w-4"})})]},S)}),(!n.allow_reflect||n.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(N,{onClick:f,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加共享组"]})]}),e.jsxs("div",{className:"space-y-4",children:[n.expression_groups.map((y,S)=>{const C=n.learning_list.map(M=>M[0]).filter(M=>M!=="");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,y.length===1&&y[0]==="*"&&"(全局共享)"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{onClick:()=>p(S),size:"sm",variant:"outline",children:e.jsx(xt,{className:"h-4 w-4"})}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除共享组 ",S+1," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>j(S),children:"删除"})]})]})]})]})]}),e.jsx("div",{className:"space-y-2",children:y.map((M,F)=>e.jsx(H0,{member:M,groupIndex:S,memberIndex:F,availableChatIds:C,onUpdate:v,onRemove:w},`${S}-${F}`))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:'提示:可以从下拉框选择已配置的聊天流,或手动输入。输入 "*" 启用全局共享'})]},S)}),n.expression_groups.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无共享组,点击"添加共享组"开始配置'})]})]})})]})}function G0({emojiConfig:n,memoryConfig:i,toolConfig:c,onEmojiChange:d,onMemoryChange:h,onToolChange:x}){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(Xe,{id:"enable_tool",checked:c.enable_tool,onCheckedChange:f=>x({...c,enable_tool:f})}),e.jsx(b,{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-2",children:[e.jsx(b,{htmlFor:"max_agent_iterations",children:"记忆思考深度"}),e.jsx(oe,{id:"max_agent_iterations",type:"number",min:"1",value:i.max_agent_iterations,onChange:f=>h({...i,max_agent_iterations:parseInt(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"最低为 1(不深入思考)"})]})]})}),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(b,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsx(oe,{id:"emoji_chance",type:"number",step:"0.1",min:"0",max:"1",value:n.emoji_chance,onChange:f=>d({...n,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(b,{htmlFor:"max_reg_num",children:"最大注册数量"}),e.jsx(oe,{id:"max_reg_num",type:"number",min:"1",value:n.max_reg_num,onChange:f=>d({...n,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(b,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(oe,{id:"check_interval",type:"number",min:"1",value:n.check_interval,onChange:f=>d({...n,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(Xe,{id:"do_replace",checked:n.do_replace,onCheckedChange:f=>d({...n,do_replace:f})}),e.jsx(b,{htmlFor:"do_replace",className:"cursor-pointer",children:"达到最大数量时替换表情包"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Xe,{id:"steal_emoji",checked:n.steal_emoji,onCheckedChange:f=>d({...n,steal_emoji:f})}),e.jsx(b,{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(Xe,{id:"content_filtration",checked:n.content_filtration,onCheckedChange:f=>d({...n,content_filtration:f})}),e.jsx(b,{htmlFor:"content_filtration",className:"cursor-pointer",children:"启用表情包过滤"})]}),n.content_filtration&&e.jsxs("div",{className:"grid gap-2 pl-6 border-l-2 border-primary/20",children:[e.jsx(b,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(oe,{id:"filtration_prompt",value:n.filtration_prompt,onChange:f=>d({...n,filtration_prompt:f.target.value}),placeholder:"符合公序良俗"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只有符合此要求的表情包才会被保存"})]})]})]})})]})}function V0({keywordReactionConfig:n,responsePostProcessConfig:i,chineseTypoConfig:c,responseSplitterConfig:d,onKeywordReactionChange:h,onResponsePostProcessChange:x,onChineseTypoChange:f,onResponseSplitterChange:j}){const p=()=>{h({...n,regex_rules:[...n.regex_rules,{regex:[""],reaction:""}]})},w=A=>{h({...n,regex_rules:n.regex_rules.filter((V,Q)=>Q!==A)})},v=(A,V,Q)=>{const T=[...n.regex_rules];V==="regex"&&typeof Q=="string"?T[A]={...T[A],regex:[Q]}:V==="reaction"&&typeof Q=="string"&&(T[A]={...T[A],reaction:Q}),h({...n,regex_rules:T})},y=({regex:A,reaction:V,onRegexChange:Q,onReactionChange:T})=>{const[D,ne]=u.useState(!1),[xe,_e]=u.useState(""),[Se,ge]=u.useState(null),[ye,be]=u.useState(""),[z,X]=u.useState({}),[k,se]=u.useState(""),_=u.useRef(null),[ue,ie]=u.useState("build"),ae=G=>G.replace(/\(\?P<([^>]+)>/g,"(?<$1>"),fe=(G,P=0)=>{const B=_.current;if(!B)return;const W=B.selectionStart||0,Ce=B.selectionEnd||0,Me=A.substring(0,W)+G+A.substring(Ce);Q(Me),setTimeout(()=>{const re=W+G.length+P;B.setSelectionRange(re,re),B.focus()},0)};u.useEffect(()=>{if(!A||!xe){ge(null),X({}),se(V),be("");return}try{const G=ae(A),P=new RegExp(G,"g"),B=xe.match(P);ge(B),be("");const Ce=new RegExp(G).exec(xe);if(Ce&&Ce.groups){X(Ce.groups);let Me=V;Object.entries(Ce.groups).forEach(([re,De])=>{Me=Me.replace(new RegExp(`\\[${re}\\]`,"g"),De||"")}),se(Me)}else X({}),se(V)}catch(G){be(G.message),ge(null),X({}),se(V)}},[A,xe,V]);const Ne=()=>{if(!xe||!Se||Se.length===0)return e.jsx("span",{className:"text-muted-foreground",children:xe||"请输入测试文本"});try{const G=ae(A),P=new RegExp(G,"g");let B=0;const W=[];let Ce;for(;(Ce=P.exec(xe))!==null;)Ce.index>B&&W.push(e.jsx("span",{children:xe.substring(B,Ce.index)},`text-${B}`)),W.push(e.jsx("span",{className:"bg-yellow-200 dark:bg-yellow-900 font-semibold",children:Ce[0]},`match-${Ce.index}`)),B=Ce.index+Ce[0].length;return B)",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($s,{open:D,onOpenChange:ne,children:[e.jsx(Xu,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Vu,{className:"h-4 w-4 mr-1"}),"正则编辑器"]})}),e.jsxs(Bs,{className:"max-w-[95vw] sm:max-w-[900px] max-h-[90vh]",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"正则表达式编辑器"}),e.jsx(Is,{className:"text-sm",children:"使用可视化工具构建正则表达式,并实时测试效果"})]}),e.jsx(ss,{className:"max-h-[calc(90vh-120px)]",children:e.jsxs(La,{value:ue,onValueChange:G=>ie(G),className:"w-full",children:[e.jsxs(wa,{className:"grid w-full grid-cols-2",children:[e.jsx(fs,{value:"build",children:"🔧 构建器"}),e.jsx(fs,{value:"test",children:"🧪 测试器"})]}),e.jsxs(Ms,{value:"build",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"正则表达式"}),e.jsx(oe,{ref:_,value:A,onChange:G=>Q(G.target.value),className:"font-mono text-sm",placeholder:"点击下方按钮构建正则表达式..."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"Reaction 内容"}),e.jsx(Fs,{value:V,onChange:G=>T(G.target.value),placeholder:"使用 [捕获组名] 引用捕获的内容...",rows:3,className:"text-sm"})]}),e.jsxs("div",{className:"space-y-4 border-t pt-4",children:[me.map(G=>e.jsxs("div",{className:"space-y-2",children:[e.jsx("h5",{className:"text-xs font-semibold text-primary",children:G.category}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:G.items.map(P=>e.jsx(N,{variant:"outline",size:"sm",className:"justify-start h-auto py-2 px-3",onClick:()=>fe(P.pattern,P.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:P.label}),e.jsx("code",{className:"ml-auto text-xs bg-muted px-1.5 py-0.5 rounded font-mono",children:P.pattern})]}),e.jsx("span",{className:"text-xs text-muted-foreground mt-0.5",children:P.desc})]})},P.label))})]},G.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(N,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>Q("^(?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(N,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>Q("(?:[^,。.\\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(N,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>Q("(?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(Ms,{value:"test",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"当前正则表达式"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:A||"(未设置)"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"test-text",className:"text-sm font-medium",children:"测试文本"}),e.jsx(Fs,{id:"test-text",value:xe,onChange:G=>_e(G.target.value),placeholder:`在此输入要测试的文本... -例如:打游戏是这样的`,className:"min-h-[100px] text-sm"})]}),ye&&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:ye})]}),!ye&&xe&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"flex items-center gap-2",children:Se&&Se.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:["匹配成功 (",Se.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(b,{className:"text-sm font-medium",children:"匹配高亮"}),e.jsx(ss,{className:"h-40 rounded-md bg-muted p-3",children:e.jsx("div",{className:"text-sm break-words",children:Ne()})})]}),Object.keys(z).length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"命名捕获组"}),e.jsx(ss,{className:"h-32 rounded-md border p-3",children:e.jsx("div",{className:"space-y-2",children:Object.entries(z).map(([G,P])=>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:["[",G,"]"]}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:"font-mono bg-muted px-2 py-0.5 rounded",children:P})]},G))})})]}),Object.keys(z).length>0&&V&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"Reaction 替换预览"}),e.jsx(ss,{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:k})}),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:"如需修改正则,切换回构建器标签页"})]})]})]})]})})]})]})},S=()=>{h({...n,keyword_rules:[...n.keyword_rules,{keywords:[],reaction:""}]})},C=A=>{h({...n,keyword_rules:n.keyword_rules.filter((V,Q)=>Q!==A)})},M=(A,V,Q)=>{const T=[...n.keyword_rules];typeof Q=="string"&&(T[A]={...T[A],reaction:Q}),h({...n,keyword_rules:T})},F=A=>{const V=[...n.keyword_rules];V[A]={...V[A],keywords:[...V[A].keywords||[],""]},h({...n,keyword_rules:V})},U=(A,V)=>{const Q=[...n.keyword_rules];Q[A]={...Q[A],keywords:(Q[A].keywords||[]).filter((T,D)=>D!==V)},h({...n,keyword_rules:Q})},O=(A,V,Q)=>{const T=[...n.keyword_rules],D=[...T[A].keywords||[]];D[V]=Q,T[A]={...T[A],keywords:D},h({...n,keyword_rules:T})},K=({rule:A})=>{const V=`{ regex = [${(A.regex||[]).map(Q=>`"${Q}"`).join(", ")}], reaction = "${A.reaction}" }`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(_a,{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(ss,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs break-all",children:V})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},H=({rule:A})=>{const V=`[[keyword_reaction.keyword_rules]] -keywords = [${(A.keywords||[]).map(Q=>`"${Q}"`).join(", ")}] -reaction = "${A.reaction}"`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(_a,{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(ss,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs whitespace-pre-wrap break-all",children:V})}),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(N,{onClick:p,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加正则规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[n.regex_rules.map((A,V)=>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:["正则规则 ",V+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(y,{regex:A.regex&&A.regex[0]||"",reaction:A.reaction,onRegexChange:Q=>v(V,"regex",Q),onReactionChange:Q=>v(V,"reaction",Q)}),e.jsx(K,{rule:A}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除正则规则 ",V+1," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>w(V),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"正则表达式(Python 语法)"}),e.jsx(oe,{value:A.regex&&A.regex[0]||"",onChange:Q=>v(V,"regex",Q.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(b,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Fs,{value:A.reaction,onChange:Q=>v(V,"reaction",Q.target.value),placeholder:`触发后麦麦的反应... -可以使用 [捕获组名] 来引用正则表达式中的内容`,rows:3,className:"text-sm"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"使用 [捕获组名] 引用正则表达式中的命名捕获组,例如 [n] 会被替换为捕获的内容"})]})]})]},V)),n.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(N,{onClick:S,size:"sm",variant:"outline",children:[e.jsx(xt,{className:"h-4 w-4 mr-1"}),"添加关键词规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[n.keyword_rules.map((A,V)=>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:["关键词规则 ",V+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(H,{rule:A}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除关键词规则 ",V+1," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>C(V),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(b,{className:"text-xs font-medium",children:"关键词列表"}),e.jsxs(N,{onClick:()=>F(V),size:"sm",variant:"ghost",children:[e.jsx(xt,{className:"h-3 w-3 mr-1"}),"添加关键词"]})]}),e.jsxs("div",{className:"space-y-2",children:[(A.keywords||[]).map((Q,T)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(oe,{value:Q,onChange:D=>O(V,T,D.target.value),placeholder:"关键词",className:"flex-1"}),e.jsx(N,{onClick:()=>U(V,T),size:"sm",variant:"ghost",children:e.jsx(ls,{className:"h-4 w-4"})})]},T)),(!A.keywords||A.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(b,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Fs,{value:A.reaction,onChange:Q=>M(V,"reaction",Q.target.value),placeholder:"触发后麦麦的反应...",rows:3,className:"text-sm"})]})]})]},V)),n.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(Xe,{id:"enable_response_post_process",checked:i.enable_response_post_process,onCheckedChange:A=>x({...i,enable_response_post_process:A})}),e.jsx(b,{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(Xe,{id:"enable_chinese_typo",checked:c.enable,onCheckedChange:A=>f({...c,enable:A})}),e.jsx(b,{htmlFor:"enable_chinese_typo",className:"cursor-pointer font-semibold",children:"中文错别字生成器"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mb-4",children:"为回复添加随机错别字,让麦麦的回复更自然"}),c.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(b,{htmlFor:"error_rate",className:"text-xs font-medium",children:"单字替换概率"}),e.jsx(oe,{id:"error_rate",type:"number",step:"0.001",min:"0",max:"1",value:c.error_rate,onChange:A=>f({...c,error_rate:parseFloat(A.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"min_freq",className:"text-xs font-medium",children:"最小字频阈值"}),e.jsx(oe,{id:"min_freq",type:"number",min:"0",value:c.min_freq,onChange:A=>f({...c,min_freq:parseInt(A.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"tone_error_rate",className:"text-xs font-medium",children:"声调错误概率"}),e.jsx(oe,{id:"tone_error_rate",type:"number",step:"0.01",min:"0",max:"1",value:c.tone_error_rate,onChange:A=>f({...c,tone_error_rate:parseFloat(A.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"word_replace_rate",className:"text-xs font-medium",children:"整词替换概率"}),e.jsx(oe,{id:"word_replace_rate",type:"number",step:"0.001",min:"0",max:"1",value:c.word_replace_rate,onChange:A=>f({...c,word_replace_rate:parseFloat(A.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(Xe,{id:"enable_response_splitter",checked:d.enable,onCheckedChange:A=>j({...d,enable:A})}),e.jsx(b,{htmlFor:"enable_response_splitter",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(b,{htmlFor:"max_length",className:"text-xs font-medium",children:"最大长度"}),e.jsx(oe,{id:"max_length",type:"number",min:"1",value:d.max_length,onChange:A=>j({...d,max_length:parseInt(A.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"回复允许的最大字符数"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"max_sentence_num",className:"text-xs font-medium",children:"最大句子数"}),e.jsx(oe,{id:"max_sentence_num",type:"number",min:"1",value:d.max_sentence_num,onChange:A=>j({...d,max_sentence_num:parseInt(A.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(Xe,{id:"enable_kaomoji_protection",checked:d.enable_kaomoji_protection,onCheckedChange:A=>j({...d,enable_kaomoji_protection:A})}),e.jsx(b,{htmlFor:"enable_kaomoji_protection",className:"cursor-pointer",children:"启用颜文字保护"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Xe,{id:"enable_overflow_return_all",checked:d.enable_overflow_return_all,onCheckedChange:A=>j({...d,enable_overflow_return_all:A})}),e.jsx(b,{htmlFor:"enable_overflow_return_all",className:"cursor-pointer",children:"超出时一次性返回全部"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"当句子数量超出限制时,合并后一次性返回所有内容"})]})]})})]})]})]})}function F0({config:n,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:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Xe,{checked:n.enable_mood,onCheckedChange:c=>i({...n,enable_mood:c})}),e.jsx(b,{className:"cursor-pointer",children:"启用情绪系统"})]}),n.enable_mood&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"情绪更新阈值"}),e.jsx(oe,{type:"number",min:"1",value:n.mood_update_threshold,onChange:c=>i({...n,mood_update_threshold:parseInt(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"越高,更新越慢"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"情感特征"}),e.jsx(Fs,{value:n.emotion_style,onChange:c=>i({...n,emotion_style:c.target.value}),placeholder:"影响情绪的变化情况",rows:2})]})]})]})]})}function $0({config:n,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(Xe,{checked:n.enable_asr,onCheckedChange:c=>i({...n,enable_asr:c})}),e.jsx(b,{className:"cursor-pointer",children:"启用语音识别"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后麦麦可以识别语音消息,需要配置语音识别模型"})]})}function Q0({config:n,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(Xe,{checked:n.enable,onCheckedChange:c=>i({...n,enable:c})}),e.jsx(b,{className:"cursor-pointer",children:"启用 LPMM 知识库"})]}),n.enable&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"LPMM 模式"}),e.jsxs(He,{value:n.lpmm_mode,onValueChange:c=>i({...n,lpmm_mode:c}),children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"选择 LPMM 模式"})}),e.jsxs(Ue,{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(b,{children:"同义词搜索 TopK"}),e.jsx(oe,{type:"number",min:"1",value:n.rag_synonym_search_top_k,onChange:c=>i({...n,rag_synonym_search_top_k:parseInt(c.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"同义词阈值"}),e.jsx(oe,{type:"number",step:"0.1",min:"0",max:"1",value:n.rag_synonym_threshold,onChange:c=>i({...n,rag_synonym_threshold:parseFloat(c.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"实体提取线程数"}),e.jsx(oe,{type:"number",min:"1",value:n.info_extraction_workers,onChange:c=>i({...n,info_extraction_workers:parseInt(c.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"嵌入向量维度"}),e.jsx(oe,{type:"number",min:"1",value:n.embedding_dimension,onChange:c=>i({...n,embedding_dimension:parseInt(c.target.value)})})]})]})]})]})]})}function Y0({config:n,onChange:i}){const[c,d]=u.useState(""),[h,x]=u.useState("WARNING"),f=()=>{c&&!n.suppress_libraries.includes(c)&&(i({...n,suppress_libraries:[...n.suppress_libraries,c]}),d(""))},j=C=>{i({...n,suppress_libraries:n.suppress_libraries.filter(M=>M!==C)})},p=()=>{c&&!n.library_log_levels[c]&&(i({...n,library_log_levels:{...n.library_log_levels,[c]:h}}),d(""),x("WARNING"))},w=C=>{const M={...n.library_log_levels};delete M[C],i({...n,library_log_levels:M})},v=["DEBUG","INFO","WARNING","ERROR","CRITICAL"],y=["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(b,{children:"日期格式"}),e.jsx(oe,{value:n.date_style,onChange:C=>i({...n,date_style:C.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(b,{children:"日志级别样式"}),e.jsxs(He,{value:n.log_level_style,onValueChange:C=>i({...n,log_level_style:C}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:y.map(C=>e.jsx(le,{value:C,children:C},C))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"日志文本颜色"}),e.jsxs(He,{value:n.color_text,onValueChange:C=>i({...n,color_text:C}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:S.map(C=>e.jsx(le,{value:C,children:C},C))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"全局日志级别"}),e.jsxs(He,{value:n.log_level,onValueChange:C=>i({...n,log_level:C}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:v.map(C=>e.jsx(le,{value:C,children:C},C))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"控制台日志级别"}),e.jsxs(He,{value:n.console_log_level,onValueChange:C=>i({...n,console_log_level:C}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:v.map(C=>e.jsx(le,{value:C,children:C},C))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"文件日志级别"}),e.jsxs(He,{value:n.file_log_level,onValueChange:C=>i({...n,file_log_level:C}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsx(Ue,{children:v.map(C=>e.jsx(le,{value:C,children:C},C))})]})]})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"mb-2 block",children:"完全屏蔽的库"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(oe,{value:c,onChange:C=>d(C.target.value),placeholder:"输入库名",className:"flex-1",onKeyDown:C=>{C.key==="Enter"&&(C.preventDefault(),f())}}),e.jsx(N,{onClick:f,size:"sm",className:"flex-shrink-0",children:e.jsx(xt,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:n.suppress_libraries.map(C=>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:C}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0",onClick:()=>j(C),children:e.jsx(ls,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},C))})]}),e.jsxs("div",{children:[e.jsx(b,{className:"mb-2 block",children:"特定库的日志级别"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(oe,{value:c,onChange:C=>d(C.target.value),placeholder:"输入库名",className:"flex-1"}),e.jsxs(He,{value:h,onValueChange:x,children:[e.jsx(Le,{className:"w-32",children:e.jsx(qe,{})}),e.jsx(Ue,{children:v.map(C=>e.jsx(le,{value:C,children:C},C))})]}),e.jsx(N,{onClick:p,size:"sm",children:e.jsx(xt,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:Object.entries(n.library_log_levels).map(([C,M])=>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:C}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm text-muted-foreground",children:M}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>w(C),children:e.jsx(ls,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]})]},C))})]})]})}function X0({config:n,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(b,{children:"显示 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否在日志中显示提示词"})]}),e.jsx(Xe,{checked:n.show_prompt,onCheckedChange:c=>i({...n,show_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示回复器 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的提示词"})]}),e.jsx(Xe,{checked:n.show_replyer_prompt,onCheckedChange:c=>i({...n,show_replyer_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示回复器推理"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的推理过程"})]}),e.jsx(Xe,{checked:n.show_replyer_reasoning,onCheckedChange:c=>i({...n,show_replyer_reasoning:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示 Jargon Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示术语相关的提示词"})]}),e.jsx(Xe,{checked:n.show_jargon_prompt,onCheckedChange:c=>i({...n,show_jargon_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示记忆检索 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示记忆检索相关的提示词"})]}),e.jsx(Xe,{checked:n.show_memory_prompt,onCheckedChange:c=>i({...n,show_memory_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示 Planner Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 Planner 的提示词和原始返回结果"})]}),e.jsx(Xe,{checked:n.show_planner_prompt,onCheckedChange:c=>i({...n,show_planner_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示 LPMM 相关文段"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 LPMM 知识库找到的相关文段日志"})]}),e.jsx(Xe,{checked:n.show_lpmm_paragraph,onCheckedChange:c=>i({...n,show_lpmm_paragraph:c})})]})]})]})}function K0({config:n,onChange:i}){const[c,d]=u.useState(""),h=()=>{c&&!n.auth_token.includes(c)&&(i({...n,auth_token:[...n.auth_token,c]}),d(""))},x=f=>{i({...n,auth_token:n.auth_token.filter((j,p)=>p!==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(b,{children:"启用自定义服务器"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否使用自定义的 MaimMessage 服务器"})]}),e.jsx(Xe,{checked:n.use_custom,onCheckedChange:f=>i({...n,use_custom:f})})]}),n.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(b,{children:"主机地址"}),e.jsx(oe,{value:n.host,onChange:f=>i({...n,host:f.target.value}),placeholder:"127.0.0.1"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"端口号"}),e.jsx(oe,{type:"number",value:n.port,onChange:f=>i({...n,port:parseInt(f.target.value)}),placeholder:"8090"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"连接模式"}),e.jsxs(He,{value:n.mode,onValueChange:f=>i({...n,mode:f}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(Xe,{checked:n.use_wss,onCheckedChange:f=>i({...n,use_wss:f}),disabled:n.mode!=="ws"}),e.jsx(b,{children:"使用 WSS 安全连接"})]})]}),n.use_wss&&n.mode==="ws"&&e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"SSL 证书文件路径"}),e.jsx(oe,{value:n.cert_file,onChange:f=>i({...n,cert_file:f.target.value}),placeholder:"cert.pem"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"SSL 密钥文件路径"}),e.jsx(oe,{value:n.key_file,onChange:f=>i({...n,key_file:f.target.value}),placeholder:"key.pem"})]})]})]})]})]}),e.jsxs("div",{children:[e.jsx(b,{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(oe,{value:c,onChange:f=>d(f.target.value),placeholder:"输入认证令牌",onKeyDown:f=>{f.key==="Enter"&&(f.preventDefault(),h())}}),e.jsx(N,{onClick:h,size:"sm",children:e.jsx(xt,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:n.auth_token.map((f,j)=>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(N,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>x(j),children:e.jsx(ls,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},j))})]})]})}function J0({config:n,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(b,{children:"启用统计信息发送"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"发送匿名统计信息,帮助我们了解全球有多少只麦麦在运行"})]}),e.jsx(Xe,{checked:n.enable,onCheckedChange:c=>i({...n,enable:c})})]})]})}const hn=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:c,className:$("w-full caption-bottom text-sm",n),...i})}));hn.displayName="Table";const xn=u.forwardRef(({className:n,...i},c)=>e.jsx("thead",{ref:c,className:$("[&_tr]:border-b",n),...i}));xn.displayName="TableHeader";const fn=u.forwardRef(({className:n,...i},c)=>e.jsx("tbody",{ref:c,className:$("[&_tr:last-child]:border-0",n),...i}));fn.displayName="TableBody";const Z0=u.forwardRef(({className:n,...i},c)=>e.jsx("tfoot",{ref:c,className:$("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",n),...i}));Z0.displayName="TableFooter";const ot=u.forwardRef(({className:n,...i},c)=>e.jsx("tr",{ref:c,className:$("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",n),...i}));ot.displayName="TableRow";const Ie=u.forwardRef(({className:n,...i},c)=>e.jsx("th",{ref:c,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),...i}));Ie.displayName="TableHead";const Fe=u.forwardRef(({className:n,...i},c)=>e.jsx("td",{ref:c,className:$("px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",n),...i}));Fe.displayName="TableCell";const I0=u.forwardRef(({className:n,...i},c)=>e.jsx("caption",{ref:c,className:$("mt-4 text-sm text-muted-foreground",n),...i}));I0.displayName="TableCaption";const no=u.forwardRef(({className:n,...i},c)=>e.jsx($t,{ref:c,className:$("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",n),...i}));no.displayName=$t.displayName;const io=u.forwardRef(({className:n,...i},c)=>e.jsxs("div",{className:"flex items-center border-b px-3","cmdk-input-wrapper":"",children:[e.jsx(zt,{className:"mr-2 h-4 w-4 shrink-0 opacity-50"}),e.jsx($t.Input,{ref:c,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),...i})]}));io.displayName=$t.Input.displayName;const ro=u.forwardRef(({className:n,...i},c)=>e.jsx($t.List,{ref:c,className:$("max-h-[300px] overflow-y-auto overflow-x-hidden",n),...i}));ro.displayName=$t.List.displayName;const co=u.forwardRef((n,i)=>e.jsx($t.Empty,{ref:i,className:"py-6 text-center text-sm",...n}));co.displayName=$t.Empty.displayName;const vr=u.forwardRef(({className:n,...i},c)=>e.jsx($t.Group,{ref:c,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),...i}));vr.displayName=$t.Group.displayName;const P0=u.forwardRef(({className:n,...i},c)=>e.jsx($t.Separator,{ref:c,className:$("-mx-1 h-px bg-border",n),...i}));P0.displayName=$t.Separator.displayName;const Nr=u.forwardRef(({className:n,...i},c)=>e.jsx($t.Item,{ref:c,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),...i}));Nr.displayName=$t.Item.displayName;const jt=u.forwardRef(({className:n,...i},c)=>e.jsx(Ip,{ref:c,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),...i,children:e.jsx(tb,{className:$("grid place-content-center text-current"),children:e.jsx(sa,{className:"h-4 w-4"})})}));jt.displayName=Ip.displayName;const zg=u.createContext(null),Ag="maibot-completed-tours";function W0(){try{const n=localStorage.getItem(Ag);return n?new Set(JSON.parse(n)):new Set}catch{return new Set}}function rp(n){localStorage.setItem(Ag,JSON.stringify([...n]))}function ew({children:n}){const[i,c]=u.useState({activeTourId:null,stepIndex:0,isRunning:!1}),d=u.useRef(new Map),[,h]=u.useState(0),[x,f]=u.useState(W0),j=u.useCallback((H,A)=>{d.current.set(H,A),h(V=>V+1)},[]),p=u.useCallback(H=>{d.current.delete(H),c(A=>A.activeTourId===H?{...A,activeTourId:null,isRunning:!1,stepIndex:0}:A)},[]),w=u.useCallback((H,A=0)=>{d.current.has(H)&&c({activeTourId:H,stepIndex:A,isRunning:!0})},[]),v=u.useCallback(()=>{c(H=>({...H,isRunning:!1}))},[]),y=u.useCallback(H=>{c(A=>({...A,stepIndex:H}))},[]),S=u.useCallback(()=>{c(H=>({...H,stepIndex:H.stepIndex+1}))},[]),C=u.useCallback(()=>{c(H=>({...H,stepIndex:Math.max(0,H.stepIndex-1)}))},[]),M=u.useCallback(()=>i.activeTourId?d.current.get(i.activeTourId)||[]:[],[i.activeTourId]),F=u.useCallback(H=>{f(A=>{const V=new Set(A);return V.add(H),rp(V),V})},[]),U=u.useCallback(H=>{const{action:A,index:V,status:Q,type:T}=H,D=["finished","skipped"];if(A==="close"){c(ne=>({...ne,isRunning:!1,stepIndex:0}));return}D.includes(Q)?c(ne=>(Q==="finished"&&ne.activeTourId&&setTimeout(()=>F(ne.activeTourId),0),{...ne,isRunning:!1,stepIndex:0})):T==="step:after"&&(A==="next"?c(ne=>({...ne,stepIndex:V+1})):A==="prev"&&c(ne=>({...ne,stepIndex:V-1})))},[F]),O=u.useCallback(H=>x.has(H),[x]),K=u.useCallback(H=>{f(A=>{const V=new Set(A);return V.delete(H),rp(V),V})},[]);return e.jsx(zg.Provider,{value:{state:i,tours:d.current,registerTour:j,unregisterTour:p,startTour:w,stopTour:v,goToStep:y,nextStep:S,prevStep:C,getCurrentSteps:M,handleJoyrideCallback:U,isTourCompleted:O,markTourCompleted:F,resetTourCompleted:K},children:n})}function Zu(){const n=u.useContext(zg);if(!n)throw new Error("useTour must be used within a TourProvider");return n}const sw={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)"}},tw={back:"上一步",close:"关闭",last:"完成",next:"下一步",nextLabelWithProgress:"下一步 ({step}/{steps})",open:"打开对话框",skip:"跳过"};function aw(){const{state:n,getCurrentSteps:i,handleJoyrideCallback:c}=Zu(),d=i(),[h,x]=u.useState(!1),f=u.useRef(n.stepIndex),j=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 v=d[n.stepIndex];if(!v){x(!1);return}const y=v.target;if(y==="body"){x(!0);return}x(!1);const S=setTimeout(()=>{const C=()=>{const O=document.querySelector(y);if(O){const K=O.getBoundingClientRect();if(K.width>0&&K.height>0)return!0}return!1};if(C()){setTimeout(()=>x(!0),100);return}const M=setInterval(()=>{C()&&(clearInterval(M),setTimeout(()=>x(!0),100))},100),F=setTimeout(()=>{clearInterval(M),x(!0)},5e3),U=()=>{clearInterval(M),clearTimeout(F)};j.current=U},150);return()=>{clearTimeout(S),j.current&&(j.current(),j.current=null)}},[n.isRunning,n.stepIndex,d]);const p=u.useRef(null);if(u.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)),p.current=v,()=>{}},[]),!n.isRunning||d.length===0||!h)return null;const w=e.jsx(Yb,{steps:d,stepIndex:n.stepIndex,run:n.isRunning,continuous:!0,showSkipButton:!0,showProgress:!0,disableOverlayClose:!0,disableScrolling:!1,disableScrollParentFix:!1,callback:c,styles:sw,locale:tw,scrollOffset:80,scrollToFirstStep:!0,floaterProps:{styles:{floater:{zIndex:99999}},disableAnimation:!0}},`tour-step-${n.stepIndex}`);return p.current?lN.createPortal(w,p.current):w}const il="model-assignment-tour",Mg=[{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}],Dg={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"},or=[{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 cp(n){return n?n.replace(/\/+$/,"").toLowerCase():""}function lw(n){if(!n)return null;const i=cp(n);return or.find(c=>c.id!=="custom"&&cp(c.base_url)===i)||null}function nw(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,x]=u.useState(!1),[f,j]=u.useState(!1),[p,w]=u.useState(!1),[v,y]=u.useState(!1),[S,C]=u.useState(!1),[M,F]=u.useState(!1),[U,O]=u.useState(null),[K,H]=u.useState(null),[A,V]=u.useState("custom"),[Q,T]=u.useState(!1),[D,ne]=u.useState(!1),[xe,_e]=u.useState(null),[Se,ge]=u.useState(!1),[ye,be]=u.useState(""),[z,X]=u.useState(new Set),[k,se]=u.useState(!1),[_,ue]=u.useState(1),[ie,ae]=u.useState(20),[fe,Ne]=u.useState(""),[me,G]=u.useState({}),[P,B]=u.useState(new Set),[W,Ce]=u.useState(new Map),{toast:Me}=Gs(),re=ga(),{state:De,goToStep:Vs,registerTour:Qs}=Zu(),de=u.useRef(null),Ee=u.useRef(!0);u.useEffect(()=>{Qs(il,Mg)},[Qs]),u.useEffect(()=>{if(De.activeTourId===il&&De.isRunning){const ee=Dg[De.stepIndex];ee&&!window.location.pathname.endsWith(ee.replace("/config/",""))&&re({to:ee})}},[De.stepIndex,De.activeTourId,De.isRunning,re]);const ts=u.useRef(De.stepIndex);u.useEffect(()=>{if(De.activeTourId===il&&De.isRunning){const ee=ts.current,we=De.stepIndex;ee>=3&&ee<=9&&we<3&&F(!1),ee>=10&&we>=3&&we<=9&&(G({}),V("custom"),O({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10}),H(null),ge(!1),F(!0)),ts.current=we}},[De.stepIndex,De.activeTourId,De.isRunning]),u.useEffect(()=>{if(De.activeTourId!==il||!De.isRunning)return;const ee=we=>{const Ge=we.target,pt=De.stepIndex;pt===2&&Ge.closest('[data-tour="add-provider-button"]')?setTimeout(()=>Vs(3),300):pt===9&&Ge.closest('[data-tour="provider-cancel-button"]')&&setTimeout(()=>Vs(10),300)};return document.addEventListener("click",ee,!0),()=>document.removeEventListener("click",ee,!0)},[De,Vs]),u.useEffect(()=>{Ke()},[]);const Ke=async()=>{try{d(!0);const ee=await ni();i(ee.api_providers||[]),w(!1),Ee.current=!1}catch(ee){console.error("加载配置失败:",ee)}finally{d(!1)}},lt=async()=>{try{y(!0),lo().catch(()=>{}),C(!0)}catch(ee){console.error("重启失败:",ee),C(!1),Me({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),y(!1)}},Ot=async()=>{try{x(!0),de.current&&clearTimeout(de.current);const ee=await ni();ee.api_providers=n,await to(ee),w(!1),Me({title:"保存成功",description:"正在重启麦麦..."}),await lt()}catch(ee){console.error("保存配置失败:",ee),Me({title:"保存失败",description:ee.message,variant:"destructive"}),x(!1)}},bt=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},Pe=()=>{C(!1),y(!1),Me({title:"重启超时",description:"服务未能在预期时间内恢复,请手动检查或刷新页面",variant:"destructive"})},R=u.useCallback(async ee=>{if(!Ee.current)try{j(!0),await Uu("api_providers",ee),w(!1)}catch(we){console.error("自动保存失败:",we),w(!0)}finally{j(!1)}},[]);u.useEffect(()=>{if(!Ee.current)return w(!0),de.current&&clearTimeout(de.current),de.current=setTimeout(()=>{R(n)},2e3),()=>{de.current&&clearTimeout(de.current)}},[n,R]);const Re=async()=>{try{x(!0),de.current&&clearTimeout(de.current);const ee=await ni();ee.api_providers=n,await to(ee),w(!1),Me({title:"保存成功",description:"模型提供商配置已保存"})}catch(ee){console.error("保存配置失败:",ee),Me({title:"保存失败",description:ee.message,variant:"destructive"})}finally{x(!1)}},ze=(ee,we)=>{if(G({}),ee){const Ge=or.find(pt=>pt.base_url===ee.base_url&&pt.client_type===ee.client_type);V(Ge?.id||"custom"),O(ee)}else V("custom"),O({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10});H(we),ge(!1),F(!0)},$e=ee=>{V(ee),T(!1);const we=or.find(Ge=>Ge.id===ee);we&&we.id!=="custom"?O(Ge=>({...Ge,name:we.name,base_url:we.base_url,client_type:we.client_type})):we?.id==="custom"&&O(Ge=>({...Ge,name:"",base_url:"",client_type:"openai"}))},Es=u.useMemo(()=>A!=="custom",[A]),We=async()=>{if(U?.api_key)try{await navigator.clipboard.writeText(U.api_key),Me({title:"复制成功",description:"API Key 已复制到剪贴板"})}catch{Me({title:"复制失败",description:"无法访问剪贴板",variant:"destructive"})}},nt=()=>{if(!U)return;const ee={};if(U.name?.trim()||(ee.name="请输入提供商名称"),U.base_url?.trim()||(ee.base_url="请输入基础 URL"),U.api_key?.trim()||(ee.api_key="请输入 API Key"),Object.keys(ee).length>0){G(ee);return}G({});const we={...U,max_retry:U.max_retry??2,timeout:U.timeout??30,retry_interval:U.retry_interval??10};if(K!==null){const Ge=[...n];Ge[K]=we,i(Ge)}else i([...n,we]);F(!1),O(null),H(null)},vs=ee=>{if(!ee&&U){const we={...U,max_retry:U.max_retry??2,timeout:U.timeout??30,retry_interval:U.retry_interval??10};O(we)}F(ee)},ke=ee=>{_e(ee),ne(!0)},ve=()=>{if(xe!==null){const ee=n.filter((we,Ge)=>Ge!==xe);i(ee),Me({title:"删除成功",description:"提供商已从列表中移除"})}ne(!1),_e(null)},ns=ee=>{const we=new Set(z);we.has(ee)?we.delete(ee):we.add(ee),X(we)},_s=()=>{if(z.size===Ys.length)X(new Set);else{const ee=Ys.map((we,Ge)=>n.findIndex(pt=>pt===Ys[Ge]));X(new Set(ee))}},At=()=>{if(z.size===0){Me({title:"提示",description:"请先选择要删除的提供商",variant:"default"});return}se(!0)},Ps=()=>{const ee=n.filter((we,Ge)=>!z.has(Ge));i(ee),X(new Set),se(!1),Me({title:"批量删除成功",description:`已删除 ${z.size} 个提供商`})},Ys=n.filter(ee=>{if(!ye)return!0;const we=ye.toLowerCase();return ee.name.toLowerCase().includes(we)||ee.base_url.toLowerCase().includes(we)||ee.client_type.toLowerCase().includes(we)}),Et=Math.ceil(Ys.length/ie),Rt=Ys.slice((_-1)*ie,_*ie),Ha=()=>{const ee=parseInt(fe);ee>=1&&ee<=Et&&(ue(ee),Ne(""))},Qt=async ee=>{B(we=>new Set(we).add(ee));try{const we=await E0(ee);Ce(Ge=>new Map(Ge).set(ee,we)),we.network_ok?we.api_key_valid===!0?Me({title:"连接正常",description:`${ee} 网络连接正常,API Key 有效 (${we.latency_ms}ms)`}):we.api_key_valid===!1?Me({title:"连接正常但 Key 无效",description:`${ee} 网络连接正常,但 API Key 无效或已过期`,variant:"destructive"}):Me({title:"网络连接正常",description:`${ee} 可以访问 (${we.latency_ms}ms)`}):Me({title:"连接失败",description:we.error||"无法连接到提供商",variant:"destructive"})}catch(we){Me({title:"测试失败",description:we.message,variant:"destructive"})}finally{B(we=>{const Ge=new Set(we);return Ge.delete(ee),Ge})}},qa=async()=>{for(const ee of n)await Qt(ee.name)},Sa=ee=>{const we=P.has(ee),Ge=W.get(ee);return we?e.jsxs(Ye,{variant:"secondary",className:"gap-1",children:[e.jsx(kt,{className:"h-3 w-3 animate-spin"}),"测试中"]}):Ge?Ge.network_ok?Ge.api_key_valid===!0?e.jsxs(Ye,{className:"gap-1 bg-green-600 hover:bg-green-700",children:[e.jsx(fa,{className:"h-3 w-3"}),"正常"]}):Ge.api_key_valid===!1?e.jsxs(Ye,{variant:"destructive",className:"gap-1",children:[e.jsx(Oa,{className:"h-3 w-3"}),"Key无效"]}):e.jsxs(Ye,{className:"gap-1 bg-blue-600 hover:bg-blue-700",children:[e.jsx(fa,{className:"h-3 w-3"}),"可访问"]}):e.jsxs(Ye,{variant:"destructive",className:"gap-1",children:[e.jsx(ng,{className:"h-3 w-3"}),"离线"]}):null};return c?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:[z.size>0&&e.jsxs(N,{onClick:At,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(ls,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",z.size,")"]}),e.jsxs(N,{onClick:qa,size:"sm",variant:"outline",className:"w-full sm:w-auto",disabled:n.length===0||P.size>0,children:[e.jsx(cn,{className:"mr-2 h-4 w-4"}),P.size>0?`测试中 (${P.size})`:"测试全部"]}),e.jsxs(N,{onClick:()=>ze(null,null),size:"sm",className:"w-full sm:w-auto","data-tour":"add-provider-button",children:[e.jsx(xt,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"添加提供商"]}),e.jsxs(N,{onClick:Re,disabled:h||f||!p||v,size:"sm",variant:"outline",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(yr,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),h?"保存中...":f?"自动保存中...":p?"保存配置":"已保存"]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{disabled:h||f||v,size:"sm",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(br,{className:"mr-2 h-4 w-4"}),v?"重启中...":p?"保存并重启":"重启麦麦"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认重启麦麦?"}),e.jsx(ds,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:p?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:p?Ot:lt,children:p?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(cl,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ol,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(ss,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{placeholder:"搜索提供商名称、URL 或类型...",value:ye,onChange:ee=>be(ee.target.value),className:"pl-9"})]}),ye&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Ys.length," 个结果"]})]}),e.jsx("div",{className:"md:hidden space-y-3",children:Ys.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 rounded-lg border bg-card",children:ye?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'}):Rt.map((ee,we)=>{const Ge=n.findIndex(pt=>pt===ee);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:ee.name}),Sa(ee.name)]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 break-all",children:ee.base_url})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>Qt(ee.name),disabled:P.has(ee.name),title:"测试连接",children:P.has(ee.name)?e.jsx(kt,{className:"h-4 w-4 animate-spin"}):e.jsx(cn,{className:"h-4 w-4"})}),e.jsx(N,{variant:"default",size:"sm",onClick:()=>ze(ee,Ge),children:e.jsx(on,{className:"h-4 w-4",strokeWidth:2,fill:"none"})}),e.jsx(N,{size:"sm",onClick:()=>ke(Ge),className:"bg-red-600 hover:bg-red-700 text-white",children:e.jsx(ls,{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:ee.client_type})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"最大重试"}),e.jsx("p",{className:"font-medium",children:ee.max_retry})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"超时(秒)"}),e.jsx("p",{className:"font-medium",children:ee.timeout})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"重试间隔(秒)"}),e.jsx("p",{className:"font-medium",children:ee.retry_interval})]})]})]},we)})}),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(hn,{children:[e.jsx(xn,{children:e.jsxs(ot,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:z.size===Ys.length&&Ys.length>0,onCheckedChange:_s})}),e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{children:"名称"}),e.jsx(Ie,{children:"基础URL"}),e.jsx(Ie,{children:"客户端类型"}),e.jsx(Ie,{className:"text-right",children:"最大重试"}),e.jsx(Ie,{className:"text-right",children:"超时(秒)"}),e.jsx(Ie,{className:"text-right",children:"重试间隔(秒)"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:Rt.length===0?e.jsx(ot,{children:e.jsx(Fe,{colSpan:9,className:"text-center text-muted-foreground py-8",children:ye?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'})}):Rt.map((ee,we)=>{const Ge=n.findIndex(pt=>pt===ee);return e.jsxs(ot,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:z.has(Ge),onCheckedChange:()=>ns(Ge)})}),e.jsx(Fe,{children:Sa(ee.name)||e.jsx(Ye,{variant:"outline",className:"text-muted-foreground",children:"未测试"})}),e.jsx(Fe,{className:"font-medium",children:ee.name}),e.jsx(Fe,{className:"max-w-xs truncate",title:ee.base_url,children:ee.base_url}),e.jsx(Fe,{children:ee.client_type}),e.jsx(Fe,{className:"text-right",children:ee.max_retry}),e.jsx(Fe,{className:"text-right",children:ee.timeout}),e.jsx(Fe,{className:"text-right",children:ee.retry_interval}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>Qt(ee.name),disabled:P.has(ee.name),title:"测试连接",children:P.has(ee.name)?e.jsx(kt,{className:"h-4 w-4 animate-spin"}):e.jsx(cn,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"default",size:"sm",onClick:()=>ze(ee,Ge),children:[e.jsx(on,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>ke(Ge),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ls,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},we)})})]})})}),Ys.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(b,{htmlFor:"page-size-provider",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(He,{value:ie.toString(),onValueChange:ee=>{ae(parseInt(ee)),ue(1),X(new Set)},children:[e.jsx(Le,{id:"page-size-provider",className:"w-20",children:e.jsx(qe,{})}),e.jsxs(Ue,{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:["显示 ",(_-1)*ie+1," 到"," ",Math.min(_*ie,Ys.length)," 条,共 ",Ys.length," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>ue(1),disabled:_===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>ue(ee=>Math.max(1,ee-1)),disabled:_===1,children:[e.jsx(Hl,{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(oe,{type:"number",value:fe,onChange:ee=>Ne(ee.target.value),onKeyDown:ee=>ee.key==="Enter"&&Ha(),placeholder:_.toString(),className:"w-16 h-8 text-center",min:1,max:Et}),e.jsx(N,{variant:"outline",size:"sm",onClick:Ha,disabled:!fe,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>ue(ee=>ee+1),disabled:_>=Et,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>ue(Et),disabled:_>=Et,className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]}),e.jsx($s,{open:M,onOpenChange:vs,children:e.jsxs(Bs,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"provider-dialog",preventOutsideClose:De.isRunning,children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:K!==null?"编辑提供商":"添加提供商"}),e.jsx(Is,{children:"配置 API 提供商的连接信息和参数"})]}),e.jsxs("form",{onSubmit:ee=>{ee.preventDefault(),nt()},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(b,{htmlFor:"template",children:"提供商模板"}),e.jsxs(Ua,{open:Q,onOpenChange:T,children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",role:"combobox","aria-expanded":Q,className:"w-full justify-between",children:[A?or.find(ee=>ee.id===A)?.display_name:"选择提供商模板...",e.jsx(Fu,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e.jsx(_a,{className:"p-0",align:"start",style:{width:"var(--radix-popover-trigger-width)"},children:e.jsxs(no,{children:[e.jsx(io,{placeholder:"搜索提供商模板..."}),e.jsx(ss,{className:"h-[300px]",children:e.jsxs(ro,{className:"max-h-none overflow-visible",children:[e.jsx(co,{children:"未找到匹配的模板"}),e.jsx(vr,{children:or.map(ee=>e.jsxs(Nr,{value:ee.display_name,onSelect:()=>$e(ee.id),children:[e.jsx(sa,{className:`mr-2 h-4 w-4 ${A===ee.id?"opacity-100":"opacity-0"}`}),ee.display_name]},ee.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(b,{htmlFor:"name",className:me.name?"text-destructive":"",children:"名称 *"}),e.jsx(oe,{id:"name",value:U?.name||"",onChange:ee=>{O(we=>we?{...we,name:ee.target.value}:null),me.name&&G(we=>({...we,name:void 0}))},placeholder:"例如: DeepSeek, SiliconFlow",className:me.name?"border-destructive focus-visible:ring-destructive":""}),me.name&&e.jsx("p",{className:"text-xs text-destructive",children:me.name})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-url-input",children:[e.jsx(b,{htmlFor:"base_url",className:me.base_url?"text-destructive":"",children:"基础 URL *"}),e.jsx(oe,{id:"base_url",value:U?.base_url||"",onChange:ee=>{O(we=>we?{...we,base_url:ee.target.value}:null),me.base_url&&G(we=>({...we,base_url:void 0}))},placeholder:"https://api.example.com/v1",disabled:Es,className:`${Es?"bg-muted cursor-not-allowed":""} ${me.base_url?"border-destructive focus-visible:ring-destructive":""}`}),me.base_url&&e.jsx("p",{className:"text-xs text-destructive",children:me.base_url}),Es&&!me.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(b,{htmlFor:"api_key",className:me.api_key?"text-destructive":"",children:"API Key *"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(oe,{id:"api_key",type:Se?"text":"password",value:U?.api_key||"",onChange:ee=>{O(we=>we?{...we,api_key:ee.target.value}:null),me.api_key&&G(we=>({...we,api_key:void 0}))},placeholder:"sk-...",className:`flex-1 ${me.api_key?"border-destructive focus-visible:ring-destructive":""}`}),e.jsx(N,{type:"button",variant:"outline",size:"icon",onClick:()=>ge(!Se),title:Se?"隐藏密钥":"显示密钥",children:Se?e.jsx(xr,{className:"h-4 w-4"}):e.jsx(Dt,{className:"h-4 w-4"})}),e.jsx(N,{type:"button",variant:"outline",size:"icon",onClick:We,title:"复制密钥",children:e.jsx(Pc,{className:"h-4 w-4"})})]}),me.api_key&&e.jsx("p",{className:"text-xs text-destructive",children:me.api_key})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"client_type",children:"客户端类型"}),e.jsxs(He,{value:U?.client_type||"openai",onValueChange:ee=>O(we=>we?{...we,client_type:ee}:null),disabled:Es,children:[e.jsx(Le,{id:"client_type",className:Es?"bg-muted cursor-not-allowed":"",children:e.jsx(qe,{placeholder:"选择客户端类型"})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"openai",children:"OpenAI"}),e.jsx(le,{value:"gemini",children:"Gemini"})]})]}),Es&&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(b,{htmlFor:"max_retry",children:"最大重试"}),e.jsx(oe,{id:"max_retry",type:"number",min:"0",value:U?.max_retry??"",onChange:ee=>{const we=ee.target.value===""?null:parseInt(ee.target.value);O(Ge=>Ge?{...Ge,max_retry:we}:null)},placeholder:"默认: 2"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"timeout",children:"超时(秒)"}),e.jsx(oe,{id:"timeout",type:"number",min:"1",value:U?.timeout??"",onChange:ee=>{const we=ee.target.value===""?null:parseInt(ee.target.value);O(Ge=>Ge?{...Ge,timeout:we}:null)},placeholder:"默认: 30"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"retry_interval",children:"重试间隔(秒)"}),e.jsx(oe,{id:"retry_interval",type:"number",min:"1",value:U?.retry_interval??"",onChange:ee=>{const we=ee.target.value===""?null:parseInt(ee.target.value);O(Ge=>Ge?{...Ge,retry_interval:we}:null)},placeholder:"默认: 10"})]})]})]}),e.jsxs(at,{children:[e.jsx(N,{type:"button",variant:"outline",onClick:()=>F(!1),"data-tour":"provider-cancel-button",children:"取消"}),e.jsx(N,{type:"submit","data-tour":"provider-save-button",children:"保存"})]})]})]})}),e.jsx(ps,{open:D,onOpenChange:ne,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除提供商 "',xe!==null?n[xe]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:ve,children:"删除"})]})]})}),e.jsx(ps,{open:k,onOpenChange:se,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认批量删除"}),e.jsxs(ds,{children:["确定要删除选中的 ",z.size," 个提供商吗? 此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:Ps,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),S&&e.jsx(Ju,{onRestartComplete:bt,onRestartFailed:Pe})]})}function iw({value:n,label:i,onRemove:c}){const{attributes:d,listeners:h,setNodeRef:x,transform:f,transition:j,isDragging:p}=ay({id:n}),w={transform:ly.Transform.toString(f),transition:j,opacity:p?.5:1},v=S=>{S.preventDefault(),S.stopPropagation(),c(n)},y=S=>{S.stopPropagation()};return e.jsx("div",{ref:x,style:w,className:$("inline-flex items-center gap-1",p&&"shadow-lg"),children:e.jsxs(Ye,{variant:"secondary",className:"cursor-move hover:bg-secondary/80 flex items-center gap-1",children:[e.jsx("div",{...d,...h,className:"cursor-grab active:cursor-grabbing flex items-center",children:e.jsx(bb,{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:S=>S.stopPropagation(),children:e.jsx(dl,{className:"h-3 w-3 cursor-pointer hover:text-destructive",strokeWidth:2,fill:"none"})})]})})}function rw({options:n,selected:i,onChange:c,placeholder:d="选择选项...",emptyText:h="未找到选项",className:x}){const[f,j]=u.useState(!1),p=Kb(Jf(ty,{activationConstraint:{distance:8}}),Jf(sy,{coordinateGetter:ey})),w=S=>{i.includes(S)?c(i.filter(C=>C!==S)):c([...i,S])},v=S=>{c(i.filter(C=>C!==S))},y=S=>{const{active:C,over:M}=S;if(M&&C.id!==M.id){const F=i.indexOf(C.id),U=i.indexOf(M.id);c(Wb(i,F,U))}};return e.jsxs(Ua,{open:f,onOpenChange:j,children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",role:"combobox","aria-expanded":f,className:$("w-full justify-between min-h-10 h-auto",x),children:[e.jsx(Jb,{sensors:p,collisionDetection:Zb,onDragEnd:y,children:e.jsx(Ib,{items:i,strategy:Pb,children:e.jsx("div",{className:"flex gap-1 flex-wrap flex-1",children:i.length===0?e.jsx("span",{className:"text-muted-foreground",children:d}):i.map(S=>{const C=n.find(M=>M.value===S);return e.jsx(iw,{value:S,label:C?.label||S,onRemove:v},S)})})})}),e.jsx(Fu,{className:"ml-2 h-4 w-4 shrink-0 opacity-50",strokeWidth:2,fill:"none"})]})}),e.jsx(_a,{className:"w-full p-0",align:"start",children:e.jsxs(no,{children:[e.jsx(io,{placeholder:"搜索...",className:"h-9"}),e.jsxs(ro,{children:[e.jsx(co,{children:h}),e.jsx(vr,{children:n.map(S=>{const C=i.includes(S.value);return e.jsxs(Nr,{value:S.value,onSelect:()=>w(S.value),children:[e.jsx("div",{className:$("mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",C?"bg-primary text-primary-foreground":"opacity-50 [&_svg]:invisible"),children:e.jsx(sa,{className:"h-3 w-3",strokeWidth:2,fill:"none"})}),e.jsx("span",{children:S.label})]},S.value)})})]})]})})]})}const op=new Map,cw=300*1e3;function ow(){const[n,i]=u.useState([]),[c,d]=u.useState([]),[h,x]=u.useState([]),[f,j]=u.useState([]),[p,w]=u.useState(null),[v,y]=u.useState(!0),[S,C]=u.useState(!1),[M,F]=u.useState(!1),[U,O]=u.useState(!1),[K,H]=u.useState(!1),[A,V]=u.useState(!1),[Q,T]=u.useState(!1),[D,ne]=u.useState(null),[xe,_e]=u.useState(null),[Se,ge]=u.useState(!1),[ye,be]=u.useState(null),[z,X]=u.useState(""),[k,se]=u.useState(new Set),[_,ue]=u.useState(!1),[ie,ae]=u.useState(1),[fe,Ne]=u.useState(20),[me,G]=u.useState(""),[P,B]=u.useState([]),[W,Ce]=u.useState(!1),[Me,re]=u.useState(null),[De,Vs]=u.useState(!1),[Qs,de]=u.useState(null),[Ee,ts]=u.useState({}),{toast:Ke}=Gs(),lt=ga(),{registerTour:Ot,startTour:bt,state:Pe,goToStep:R}=Zu(),Re=u.useRef(null),ze=u.useRef(null),$e=u.useRef(!0);u.useEffect(()=>{Ot(il,Mg)},[Ot]),u.useEffect(()=>{if(Pe.activeTourId===il&&Pe.isRunning){const Y=Dg[Pe.stepIndex];Y&&!window.location.pathname.endsWith(Y.replace("/config/",""))&<({to:Y})}},[Pe.stepIndex,Pe.activeTourId,Pe.isRunning,lt]);const Es=u.useRef(Pe.stepIndex);u.useEffect(()=>{if(Pe.activeTourId===il&&Pe.isRunning){const Y=Es.current,je=Pe.stepIndex;Y>=12&&Y<=17&&je<12&&T(!1),Es.current=je}},[Pe.stepIndex,Pe.activeTourId,Pe.isRunning]),u.useEffect(()=>{if(Pe.activeTourId!==il||!Pe.isRunning)return;const Y=je=>{const Ve=je.target,Je=Pe.stepIndex;Je===2&&Ve.closest('[data-tour="add-provider-button"]')?setTimeout(()=>R(3),300):Je===9&&Ve.closest('[data-tour="provider-cancel-button"]')?setTimeout(()=>R(10),300):Je===11&&Ve.closest('[data-tour="add-model-button"]')?setTimeout(()=>R(12),300):Je===17&&Ve.closest('[data-tour="model-cancel-button"]')?setTimeout(()=>R(18),300):Je===18&&Ve.closest('[data-tour="tasks-tab-trigger"]')&&setTimeout(()=>R(19),300)};return document.addEventListener("click",Y,!0),()=>document.removeEventListener("click",Y,!0)},[Pe,R]);const We=()=>{bt(il)};u.useEffect(()=>{nt()},[]);const nt=async()=>{try{y(!0);const Y=await ni(),je=Y.models||[];i(je),j(je.map(Je=>Je.name));const Ve=Y.api_providers||[];d(Ve.map(Je=>Je.name)),x(Ve),w(Y.model_task_config||null),O(!1),$e.current=!1}catch(Y){console.error("加载配置失败:",Y)}finally{y(!1)}},vs=u.useCallback(Y=>h.find(je=>je.name===Y),[h]),ke=u.useCallback(async(Y,je=!1)=>{const Ve=vs(Y);if(!Ve?.base_url){B([]),de(null),re('提供商配置不完整,请先在"模型提供商配置"中配置');return}if(!Ve.api_key){B([]),de(null),re('该提供商未配置 API Key,请先在"模型提供商配置"中填写');return}const Je=lw(Ve.base_url);if(de(Je),!Je?.modelFetcher){B([]),re(null);return}const Ns=`${Y}:${Ve.base_url}`,ta=op.get(Ns);if(!je&&ta&&Date.now()-ta.timestamp{Q&&D?.api_provider&&ke(D.api_provider)},[Q,D?.api_provider,ke]);const ve=async()=>{try{H(!0),lo().catch(()=>{}),V(!0)}catch(Y){console.error("重启失败:",Y),V(!1),Ke({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),H(!1)}},ns=async()=>{try{C(!0),Re.current&&clearTimeout(Re.current),ze.current&&clearTimeout(ze.current);const Y=await ni();Y.models=n,Y.model_task_config=p,await to(Y),O(!1),Ke({title:"保存成功",description:"正在重启麦麦..."}),await ve()}catch(Y){console.error("保存配置失败:",Y),Ke({title:"保存失败",description:Y.message,variant:"destructive"}),C(!1)}},_s=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},At=()=>{V(!1),H(!1),Ke({title:"重启超时",description:"服务未能在预期时间内恢复,请手动检查或刷新页面",variant:"destructive"})},Ps=u.useCallback(async Y=>{if(!$e.current)try{F(!0),await Uu("models",Y),O(!1)}catch(je){console.error("自动保存模型列表失败:",je),O(!0)}finally{F(!1)}},[]),Ys=u.useCallback(async Y=>{if(!$e.current)try{F(!0),await Uu("model_task_config",Y),O(!1)}catch(je){console.error("自动保存任务配置失败:",je),O(!0)}finally{F(!1)}},[]);u.useEffect(()=>{if(!$e.current)return O(!0),Re.current&&clearTimeout(Re.current),Re.current=setTimeout(()=>{Ps(n)},2e3),()=>{Re.current&&clearTimeout(Re.current)}},[n,Ps]),u.useEffect(()=>{if(!($e.current||!p))return O(!0),ze.current&&clearTimeout(ze.current),ze.current=setTimeout(()=>{Ys(p)},2e3),()=>{ze.current&&clearTimeout(ze.current)}},[p,Ys]);const Et=async()=>{try{C(!0),Re.current&&clearTimeout(Re.current),ze.current&&clearTimeout(ze.current);const Y=await ni();Y.models=n,Y.model_task_config=p,await to(Y),O(!1),Ke({title:"保存成功",description:"模型配置已保存"}),await nt()}catch(Y){console.error("保存配置失败:",Y),Ke({title:"保存失败",description:Y.message,variant:"destructive"})}finally{C(!1)}},Rt=(Y,je)=>{ts({}),ne(Y||{model_identifier:"",name:"",api_provider:c[0]||"",price_in:0,price_out:0,force_stream_mode:!1,extra_params:{}}),_e(je),T(!0)},Ha=()=>{if(!D)return;const Y={};if(D.name?.trim()||(Y.name="请输入模型名称"),D.api_provider?.trim()||(Y.api_provider="请选择 API 提供商"),D.model_identifier?.trim()||(Y.model_identifier="请输入模型标识符"),Object.keys(Y).length>0){ts(Y);return}ts({});const je={...D,price_in:D.price_in??0,price_out:D.price_out??0};let Ve,Je=null;if(xe!==null?(Je=n[xe].name,Ve=[...n],Ve[xe]=je):Ve=[...n,je],i(Ve),j(Ve.map(Ns=>Ns.name)),Je&&Je!==je.name&&p){const Ns=ta=>ta.map(aa=>aa===Je?je.name:aa);w({...p,utils:{...p.utils,model_list:Ns(p.utils?.model_list||[])},utils_small:{...p.utils_small,model_list:Ns(p.utils_small?.model_list||[])},tool_use:{...p.tool_use,model_list:Ns(p.tool_use?.model_list||[])},replyer:{...p.replyer,model_list:Ns(p.replyer?.model_list||[])},planner:{...p.planner,model_list:Ns(p.planner?.model_list||[])},vlm:{...p.vlm,model_list:Ns(p.vlm?.model_list||[])},voice:{...p.voice,model_list:Ns(p.voice?.model_list||[])},embedding:{...p.embedding,model_list:Ns(p.embedding?.model_list||[])},lpmm_entity_extract:{...p.lpmm_entity_extract,model_list:Ns(p.lpmm_entity_extract?.model_list||[])},lpmm_rdf_build:{...p.lpmm_rdf_build,model_list:Ns(p.lpmm_rdf_build?.model_list||[])},lpmm_qa:{...p.lpmm_qa,model_list:Ns(p.lpmm_qa?.model_list||[])}})}T(!1),ne(null),_e(null)},Qt=Y=>{if(!Y&&D){const je={...D,price_in:D.price_in??0,price_out:D.price_out??0};ne(je)}T(Y)},qa=Y=>{be(Y),ge(!0)},Sa=()=>{if(ye!==null){const Y=n.filter((je,Ve)=>Ve!==ye);i(Y),j(Y.map(je=>je.name)),Ke({title:"删除成功",description:"模型已从列表中移除"})}ge(!1),be(null)},ee=Y=>{const je=new Set(k);je.has(Y)?je.delete(Y):je.add(Y),se(je)},we=()=>{if(k.size===Lt.length)se(new Set);else{const Y=Lt.map((je,Ve)=>n.findIndex(Je=>Je===Lt[Ve]));se(new Set(Y))}},Ge=()=>{if(k.size===0){Ke({title:"提示",description:"请先选择要删除的模型",variant:"default"});return}ue(!0)},pt=()=>{const Y=n.filter((je,Ve)=>!k.has(Ve));i(Y),j(Y.map(je=>je.name)),se(new Set),ue(!1),Ke({title:"批量删除成功",description:`已删除 ${k.size} 个模型`})},Yt=(Y,je,Ve)=>{p&&w({...p,[Y]:{...p[Y],[je]:Ve}})},Lt=n.filter(Y=>{if(!z)return!0;const je=z.toLowerCase();return Y.name.toLowerCase().includes(je)||Y.model_identifier.toLowerCase().includes(je)||Y.api_provider.toLowerCase().includes(je)}),hl=Math.ceil(Lt.length/fe),Vl=Lt.slice((ie-1)*fe,ie*fe),pn=()=>{const Y=parseInt(me);Y>=1&&Y<=hl&&(ae(Y),G(""))},gn=Y=>p?[p.utils?.model_list||[],p.utils_small?.model_list||[],p.tool_use?.model_list||[],p.replyer?.model_list||[],p.planner?.model_list||[],p.vlm?.model_list||[],p.voice?.model_list||[],p.embedding?.model_list||[],p.lpmm_entity_extract?.model_list||[],p.lpmm_rdf_build?.model_list||[],p.lpmm_qa?.model_list||[]].some(Ve=>Ve.includes(Y)):!1;return v?e.jsx(ss,{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(ss,{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(N,{onClick:Et,disabled:S||M||!U||K,size:"sm",variant:"outline",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(yr,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),S?"保存中...":M?"自动保存中...":U?"保存配置":"已保存"]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{disabled:S||M||K,size:"sm",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(br,{className:"mr-2 h-4 w-4"}),K?"重启中...":U?"保存并重启":"重启麦麦"]})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认重启麦麦?"}),e.jsx(ds,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:U?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:U?ns:ve,children:U?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(cl,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ol,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(cl,{className:"hidden lg:flex border-primary/30 bg-primary/5 cursor-pointer hover:bg-primary/10 transition-colors",onClick:We,children:[e.jsx(yb,{className:"h-4 w-4 text-primary"}),e.jsxs(ol,{className:"flex items-center justify-between",children:[e.jsxs("span",{children:[e.jsx("strong",{className:"text-primary",children:"新手引导:"}),"不知道如何配置模型?点击这里开始学习如何为麦麦的组件分配模型。"]}),e.jsx(N,{variant:"outline",size:"sm",className:"ml-4 shrink-0",children:"开始引导"})]})]}),e.jsxs(La,{defaultValue:"models",className:"w-full",children:[e.jsxs(wa,{className:"grid w-full max-w-full sm:max-w-md grid-cols-2",children:[e.jsx(fs,{value:"models",children:"添加模型"}),e.jsx(fs,{value:"tasks","data-tour":"tasks-tab-trigger",children:"为模型分配功能"})]}),e.jsxs(Ms,{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:[k.size>0&&e.jsxs(N,{onClick:Ge,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(ls,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",k.size,")"]}),e.jsxs(N,{onClick:()=>Rt(null,null),size:"sm",variant:"outline",className:"w-full sm:w-auto","data-tour":"add-model-button",children:[e.jsx(xt,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{placeholder:"搜索模型名称、标识符或提供商...",value:z,onChange:Y=>X(Y.target.value),className:"pl-9"})]}),z&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Lt.length," 个结果"]})]}),e.jsx("div",{className:"md:hidden space-y-3",children:Vl.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 rounded-lg border bg-card",children:z?"未找到匹配的模型":"暂无模型配置"}):Vl.map((Y,je)=>{const Ve=n.findIndex(Ns=>Ns===Y),Je=gn(Y.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:Y.name}),e.jsx(Ye,{variant:Je?"default":"secondary",className:Je?"bg-green-600 hover:bg-green-700":"",children:Je?"已使用":"未使用"})]}),e.jsx("p",{className:"text-xs text-muted-foreground break-all",title:Y.model_identifier,children:Y.model_identifier})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>Rt(Y,Ve),children:[e.jsx(on,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>qa(Ve),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ls,{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:Y.api_provider})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"强制流式"}),e.jsx("p",{className:"font-medium",children:Y.force_stream_mode?"是":"否"})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输入价格"}),e.jsxs("p",{className:"font-medium",children:["¥",Y.price_in,"/M"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输出价格"}),e.jsxs("p",{className:"font-medium",children:["¥",Y.price_out,"/M"]})]})]})]},je)})}),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(hn,{children:[e.jsx(xn,{children:e.jsxs(ot,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:k.size===Lt.length&&Lt.length>0,onCheckedChange:we})}),e.jsx(Ie,{className:"w-24",children:"使用状态"}),e.jsx(Ie,{children:"模型名称"}),e.jsx(Ie,{children:"模型标识符"}),e.jsx(Ie,{children:"提供商"}),e.jsx(Ie,{className:"text-right",children:"输入价格"}),e.jsx(Ie,{className:"text-right",children:"输出价格"}),e.jsx(Ie,{className:"text-center",children:"强制流式"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:Vl.length===0?e.jsx(ot,{children:e.jsx(Fe,{colSpan:9,className:"text-center text-muted-foreground py-8",children:z?"未找到匹配的模型":"暂无模型配置"})}):Vl.map((Y,je)=>{const Ve=n.findIndex(Ns=>Ns===Y),Je=gn(Y.name);return e.jsxs(ot,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:k.has(Ve),onCheckedChange:()=>ee(Ve)})}),e.jsx(Fe,{children:e.jsx(Ye,{variant:Je?"default":"secondary",className:Je?"bg-green-600 hover:bg-green-700":"",children:Je?"已使用":"未使用"})}),e.jsx(Fe,{className:"font-medium",children:Y.name}),e.jsx(Fe,{className:"max-w-xs truncate",title:Y.model_identifier,children:Y.model_identifier}),e.jsx(Fe,{children:Y.api_provider}),e.jsxs(Fe,{className:"text-right",children:["¥",Y.price_in,"/M"]}),e.jsxs(Fe,{className:"text-right",children:["¥",Y.price_out,"/M"]}),e.jsx(Fe,{className:"text-center",children:Y.force_stream_mode?"是":"否"}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>Rt(Y,Ve),children:[e.jsx(on,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>qa(Ve),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ls,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},je)})})]})})}),Lt.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(b,{htmlFor:"page-size-model",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(He,{value:fe.toString(),onValueChange:Y=>{Ne(parseInt(Y)),ae(1),se(new Set)},children:[e.jsx(Le,{id:"page-size-model",className:"w-20",children:e.jsx(qe,{})}),e.jsxs(Ue,{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:["显示 ",(ie-1)*fe+1," 到"," ",Math.min(ie*fe,Lt.length)," 条,共 ",Lt.length," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>ae(1),disabled:ie===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>ae(Y=>Math.max(1,Y-1)),disabled:ie===1,children:[e.jsx(Hl,{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(oe,{type:"number",value:me,onChange:Y=>G(Y.target.value),onKeyDown:Y=>Y.key==="Enter"&&pn(),placeholder:ie.toString(),className:"w-16 h-8 text-center",min:1,max:hl}),e.jsx(N,{variant:"outline",size:"sm",onClick:pn,disabled:!me,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>ae(Y=>Y+1),disabled:ie>=hl,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>ae(hl),disabled:ie>=hl,className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]}),e.jsxs(Ms,{value:"tasks",className:"space-y-6 mt-0",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"为不同的任务配置使用的模型和参数"}),p&&e.jsxs("div",{className:"grid gap-4 sm:gap-6",children:[e.jsx(ba,{title:"组件模型 (utils)",description:"用于表情包、取名、关系、情绪变化等组件",taskConfig:p.utils,modelNames:f,onChange:(Y,je)=>Yt("utils",Y,je),dataTour:"task-model-select"}),e.jsx(ba,{title:"组件小模型 (utils_small)",description:"消耗量较大的组件,建议使用速度较快的小模型",taskConfig:p.utils_small,modelNames:f,onChange:(Y,je)=>Yt("utils_small",Y,je)}),e.jsx(ba,{title:"工具调用模型 (tool_use)",description:"需要使用支持工具调用的模型",taskConfig:p.tool_use,modelNames:f,onChange:(Y,je)=>Yt("tool_use",Y,je)}),e.jsx(ba,{title:"首要回复模型 (replyer)",description:"用于表达器和表达方式学习",taskConfig:p.replyer,modelNames:f,onChange:(Y,je)=>Yt("replyer",Y,je)}),e.jsx(ba,{title:"决策模型 (planner)",description:"负责决定麦麦该什么时候回复",taskConfig:p.planner,modelNames:f,onChange:(Y,je)=>Yt("planner",Y,je)}),e.jsx(ba,{title:"图像识别模型 (vlm)",description:"视觉语言模型",taskConfig:p.vlm,modelNames:f,onChange:(Y,je)=>Yt("vlm",Y,je),hideTemperature:!0}),e.jsx(ba,{title:"语音识别模型 (voice)",description:"语音转文字",taskConfig:p.voice,modelNames:f,onChange:(Y,je)=>Yt("voice",Y,je),hideTemperature:!0,hideMaxTokens:!0}),e.jsx(ba,{title:"嵌入模型 (embedding)",description:"用于向量化",taskConfig:p.embedding,modelNames:f,onChange:(Y,je)=>Yt("embedding",Y,je),hideTemperature:!0,hideMaxTokens:!0}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"LPMM 知识库模型"}),e.jsx(ba,{title:"实体提取模型 (lpmm_entity_extract)",description:"从文本中提取实体",taskConfig:p.lpmm_entity_extract,modelNames:f,onChange:(Y,je)=>Yt("lpmm_entity_extract",Y,je)}),e.jsx(ba,{title:"RDF 构建模型 (lpmm_rdf_build)",description:"构建知识图谱",taskConfig:p.lpmm_rdf_build,modelNames:f,onChange:(Y,je)=>Yt("lpmm_rdf_build",Y,je)}),e.jsx(ba,{title:"问答模型 (lpmm_qa)",description:"知识库问答",taskConfig:p.lpmm_qa,modelNames:f,onChange:(Y,je)=>Yt("lpmm_qa",Y,je)})]})]})]})]}),e.jsx($s,{open:Q,onOpenChange:Qt,children:e.jsxs(Bs,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"model-dialog",preventOutsideClose:Pe.isRunning,children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:xe!==null?"编辑模型":"添加模型"}),e.jsx(Is,{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(b,{htmlFor:"model_name",className:Ee.name?"text-destructive":"",children:"模型名称 *"}),e.jsx(oe,{id:"model_name",value:D?.name||"",onChange:Y=>{ne(je=>je?{...je,name:Y.target.value}:null),Ee.name&&ts(je=>({...je,name:void 0}))},placeholder:"例如: qwen3-30b",className:Ee.name?"border-destructive focus-visible:ring-destructive":""}),Ee.name?e.jsx("p",{className:"text-xs text-destructive",children:Ee.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(b,{htmlFor:"api_provider",className:Ee.api_provider?"text-destructive":"",children:"API 提供商 *"}),e.jsxs(He,{value:D?.api_provider||"",onValueChange:Y=>{ne(je=>je?{...je,api_provider:Y}:null),B([]),re(null),Ee.api_provider&&ts(je=>({...je,api_provider:void 0}))},children:[e.jsx(Le,{id:"api_provider",className:Ee.api_provider?"border-destructive focus-visible:ring-destructive":"",children:e.jsx(qe,{placeholder:"选择提供商"})}),e.jsx(Ue,{children:c.map(Y=>e.jsx(le,{value:Y,children:Y},Y))})]}),Ee.api_provider&&e.jsx("p",{className:"text-xs text-destructive",children:Ee.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(b,{htmlFor:"model_identifier",className:Ee.model_identifier?"text-destructive":"",children:"模型标识符 *"}),Qs?.modelFetcher&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ye,{variant:"secondary",className:"text-xs",children:Qs.display_name}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-6 px-2",onClick:()=>D?.api_provider&&ke(D.api_provider,!0),disabled:W,children:W?e.jsx(kt,{className:"h-3 w-3 animate-spin"}):e.jsx(Ct,{className:"h-3 w-3"})})]})]}),Qs?.modelFetcher?e.jsxs(Ua,{open:De,onOpenChange:Vs,children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",role:"combobox","aria-expanded":De,className:"w-full justify-between font-normal",disabled:W||!!Me,children:[W?e.jsxs("span",{className:"flex items-center gap-2 text-muted-foreground",children:[e.jsx(kt,{className:"h-4 w-4 animate-spin"}),"正在获取模型列表..."]}):Me?e.jsx("span",{className:"text-muted-foreground text-sm",children:"点击下方输入框手动填写"}):D?.model_identifier?e.jsx("span",{className:"truncate",children:D.model_identifier}):e.jsx("span",{className:"text-muted-foreground",children:"搜索或选择模型..."}),e.jsx(Fu,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e.jsx(_a,{className:"p-0",align:"start",style:{width:"var(--radix-popover-trigger-width)"},children:e.jsxs(no,{children:[e.jsx(io,{placeholder:"搜索模型..."}),e.jsx(ss,{className:"h-[300px]",children:e.jsxs(ro,{className:"max-h-none overflow-visible",children:[e.jsx(co,{children:Me?e.jsxs("div",{className:"py-4 px-2 text-center space-y-2",children:[e.jsx("p",{className:"text-sm text-destructive",children:Me}),!Me.includes("API Key")&&e.jsx(N,{variant:"link",size:"sm",onClick:()=>D?.api_provider&&ke(D.api_provider,!0),children:"重试"})]}):"未找到匹配的模型"}),e.jsx(vr,{heading:"可用模型",children:P.map(Y=>e.jsxs(Nr,{value:Y.id,onSelect:()=>{ne(je=>je?{...je,model_identifier:Y.id}:null),Vs(!1)},children:[e.jsx(sa,{className:`mr-2 h-4 w-4 ${D?.model_identifier===Y.id?"opacity-100":"opacity-0"}`}),e.jsxs("div",{className:"flex flex-col",children:[e.jsx("span",{children:Y.id}),Y.name!==Y.id&&e.jsx("span",{className:"text-xs text-muted-foreground",children:Y.name})]})]},Y.id))}),e.jsx(vr,{heading:"手动输入",children:e.jsxs(Nr,{value:"__manual_input__",onSelect:()=>{Vs(!1)},children:[e.jsx(on,{className:"mr-2 h-4 w-4"}),"手动输入模型标识符..."]})})]})})]})})]}):e.jsx(oe,{id:"model_identifier",value:D?.model_identifier||"",onChange:Y=>{ne(je=>je?{...je,model_identifier:Y.target.value}:null),Ee.model_identifier&&ts(je=>({...je,model_identifier:void 0}))},placeholder:"Qwen/Qwen3-30B-A3B-Instruct-2507",className:Ee.model_identifier?"border-destructive focus-visible:ring-destructive":""}),Ee.model_identifier&&e.jsx("p",{className:"text-xs text-destructive",children:Ee.model_identifier}),Me&&Qs?.modelFetcher&&!Ee.model_identifier&&e.jsxs(cl,{variant:"destructive",className:"mt-2 py-2",children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsx(ol,{className:"text-xs",children:Me})]}),Qs?.modelFetcher&&e.jsx(oe,{value:D?.model_identifier||"",onChange:Y=>{ne(je=>je?{...je,model_identifier:Y.target.value}:null),Ee.model_identifier&&ts(je=>({...je,model_identifier:void 0}))},placeholder:"或手动输入模型标识符",className:`mt-2 ${Ee.model_identifier?"border-destructive focus-visible:ring-destructive":""}`}),!Ee.model_identifier&&e.jsx("p",{className:"text-xs text-muted-foreground",children:Me?'请手动输入模型标识符,或前往"模型提供商配置"检查 API Key':Qs?.modelFetcher?`已识别为 ${Qs.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(b,{htmlFor:"price_in",children:"输入价格 (¥/M token)"}),e.jsx(oe,{id:"price_in",type:"number",step:"0.1",min:"0",value:D?.price_in??"",onChange:Y=>{const je=Y.target.value===""?null:parseFloat(Y.target.value);ne(Ve=>Ve?{...Ve,price_in:je}:null)},placeholder:"默认: 0"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"price_out",children:"输出价格 (¥/M token)"}),e.jsx(oe,{id:"price_out",type:"number",step:"0.1",min:"0",value:D?.price_out??"",onChange:Y=>{const je=Y.target.value===""?null:parseFloat(Y.target.value);ne(Ve=>Ve?{...Ve,price_out:je}:null)},placeholder:"默认: 0"})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Xe,{id:"force_stream_mode",checked:D?.force_stream_mode||!1,onCheckedChange:Y=>ne(je=>je?{...je,force_stream_mode:Y}:null)}),e.jsx(b,{htmlFor:"force_stream_mode",className:"cursor-pointer",children:"强制流式输出模式"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>T(!1),"data-tour":"model-cancel-button",children:"取消"}),e.jsx(N,{onClick:Ha,"data-tour":"model-save-button",children:"保存"})]})]})}),e.jsx(ps,{open:Se,onOpenChange:ge,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除模型 "',ye!==null?n[ye]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:Sa,children:"删除"})]})]})}),e.jsx(ps,{open:_,onOpenChange:ue,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认批量删除"}),e.jsxs(ds,{children:["确定要删除选中的 ",k.size," 个模型吗? 此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:pt,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),A&&e.jsx(Ju,{onRestartComplete:_s,onRestartFailed:At})]})})}function ba({title:n,description:i,taskConfig:c,modelNames:d,onChange:h,hideTemperature:x=!1,hideMaxTokens:f=!1,dataTour:j}){const p=w=>{h("model_list",w)};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:n}),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":j,children:[e.jsx(b,{children:"模型列表"}),e.jsx(rw,{options:d.map(w=>({label:w,value:w})),selected:c.model_list||[],onChange:p,placeholder:"选择模型...",emptyText:"暂无可用模型"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[!x&&e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{children:"温度"}),e.jsx(oe,{type:"number",step:"0.1",min:"0",max:"1",value:c.temperature??.3,onChange:w=>{const v=parseFloat(w.target.value);!isNaN(v)&&v>=0&&v<=1&&h("temperature",v)},className:"w-20 h-8 text-sm"})]}),e.jsx(Ma,{value:[c.temperature??.3],onValueChange:w=>h("temperature",w[0]),min:0,max:1,step:.1,className:"w-full"})]}),!f&&e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"最大 Token"}),e.jsx(oe,{type:"number",step:"1",min:"1",value:c.max_tokens??1024,onChange:w=>h("max_tokens",parseInt(w.target.value))})]})]})]})]})}const oo="/api/webui/config";async function dw(){const i=await(await Te(`${oo}/adapter-config/path`)).json();return!i.success||!i.path?null:{path:i.path,lastModified:i.lastModified}}async function dp(n){const c=await(await Te(`${oo}/adapter-config/path`,{method:"POST",headers:Ls(),body:JSON.stringify({path:n})})).json();if(!c.success)throw new Error(c.message||"保存路径失败")}async function up(n){const c=await(await Te(`${oo}/adapter-config?path=${encodeURIComponent(n)}`)).json();if(!c.success)throw new Error("读取配置文件失败");return c.content}async function mp(n,i){const d=await(await Te(`${oo}/adapter-config`,{method:"POST",headers:Ls(),body:JSON.stringify({path:n,content:i})})).json();if(!d.success)throw new Error(d.message||"保存配置失败")}const ea={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"}},zu={oneclick:{name:"一键包",description:"使用一键包部署的适配器配置",path:"../MaiBot-Napcat-Adapter/config.toml",icon:dn},docker:{name:"Docker",description:"Docker Compose 部署的适配器配置",path:"/MaiMBot/adapters-config/config.toml",icon:wb}};function uw(){const[n,i]=u.useState("upload"),[c,d]=u.useState(null),[h,x]=u.useState(""),[f,j]=u.useState(""),[p,w]=u.useState("oneclick"),[v,y]=u.useState(""),[S,C]=u.useState(!1),[M,F]=u.useState(!1),[U,O]=u.useState(!1),[K,H]=u.useState(!1),[A,V]=u.useState(null),Q=u.useRef(null),{toast:T}=Gs(),D=u.useRef(null),ne=G=>{if(!G.trim())return{valid:!1,error:"路径不能为空"};if(!G.toLowerCase().endsWith(".toml"))return{valid:!1,error:"文件必须是 .toml 格式"};const P=/^([a-zA-Z]:\\|\\\\[^\\]+\\[^\\]+\\).+\.toml$/i,B=/^(\/|~\/).+\.toml$/i,W=/^(\.{1,2}[\\/]|[^:\\/]).+\.toml$/i,Ce=P.test(G),Me=B.test(G),re=W.test(G);return!Ce&&!Me&&!re?{valid:!1,error:"路径格式错误"}:/[<>"|?*\x00-\x1F]/.test(G)?{valid:!1,error:"路径包含非法字符"}:{valid:!0,error:""}},xe=G=>{if(j(G),G.trim()){const P=ne(G);y(P.error)}else y("")},_e=u.useCallback(async G=>{const P=zu[G];F(!0);try{const B=await up(P.path),W=ie(B);d(W),w(G),j(P.path),await dp(P.path),T({title:"加载成功",description:`已从${P.name}预设加载配置`})}catch(B){console.error("加载预设配置失败:",B),T({title:"加载失败",description:B instanceof Error?B.message:"无法读取预设配置文件",variant:"destructive"})}finally{F(!1)}},[T]),Se=u.useCallback(async G=>{const P=ne(G);if(!P.valid){y(P.error),T({title:"路径无效",description:P.error,variant:"destructive"});return}y(""),F(!0);try{const B=await up(G),W=ie(B);d(W),j(G),await dp(G),T({title:"加载成功",description:"已从配置文件加载"})}catch(B){console.error("加载配置失败:",B),T({title:"加载失败",description:B instanceof Error?B.message:"无法读取配置文件",variant:"destructive"})}finally{F(!1)}},[T]);u.useEffect(()=>{(async()=>{try{const P=await dw();if(P&&P.path){j(P.path);const B=Object.entries(zu).find(([,W])=>W.path===P.path);B?(i("preset"),w(B[0]),await _e(B[0])):(i("path"),await Se(P.path))}}catch(P){console.error("加载保存的路径失败:",P)}})()},[Se,_e]);const ge=u.useCallback(G=>{n!=="path"&&n!=="preset"||!f||(D.current&&clearTimeout(D.current),D.current=setTimeout(async()=>{C(!0);try{const P=ae(G);await mp(f,P),T({title:"自动保存成功",description:"配置已保存到文件"})}catch(P){console.error("自动保存失败:",P),T({title:"自动保存失败",description:P instanceof Error?P.message:"保存配置失败",variant:"destructive"})}finally{C(!1)}},1e3))},[n,f,T]),ye=async()=>{if(!c||!f)return;const G=ne(f);if(!G.valid){T({title:"保存失败",description:G.error,variant:"destructive"});return}C(!0);try{const P=ae(c);await mp(f,P),T({title:"保存成功",description:"配置已保存到文件"})}catch(P){console.error("保存失败:",P),T({title:"保存失败",description:P instanceof Error?P.message:"保存配置失败",variant:"destructive"})}finally{C(!1)}},be=async()=>{f&&await Se(f)},z=G=>{if(G!==n){if(c){V(G),O(!0);return}X(G)}},X=G=>{d(null),x(""),y(""),i(G),G==="preset"&&_e("oneclick"),T({title:"已切换模式",description:{upload:"现在可以上传配置文件",path:"现在可以指定配置文件路径",preset:"现在可以使用预设配置"}[G]})},k=()=>{A&&(X(A),V(null)),O(!1)},se=()=>{if(c){H(!0);return}_()},_=()=>{j(""),d(null),y(""),T({title:"已清空",description:"路径和配置已清空"})},ue=()=>{_(),H(!1)},ie=G=>{const P=JSON.parse(JSON.stringify(ea)),B=G.split(` -`);let W="";for(const Ce of B){const Me=Ce.trim();if(!Me||Me.startsWith("#"))continue;const re=Me.match(/^\[(\w+)\]/);if(re){W=re[1];continue}const De=Me.match(/^(\w+)\s*=\s*(.+)$/);if(De&&W){const[,Vs,Qs]=De;let de=Qs.trim();const Ee=de.match(/^("[^"]*")/);if(Ee)de=Ee[1];else{const Ke=de.indexOf("#");Ke!==-1&&(de=de.substring(0,Ke).trim())}let ts;if(de==="true")ts=!0;else if(de==="false")ts=!1;else if(de.startsWith("[")&&de.endsWith("]")){const Ke=de.slice(1,-1).trim();if(Ke){const lt=Ke.split(",").map(bt=>{const Pe=bt.trim();return isNaN(Number(Pe))?Pe.replace(/"/g,""):Number(Pe)}),Ot=typeof lt[0];ts=lt.every(bt=>typeof bt===Ot)?lt:lt.filter(bt=>typeof bt=="number")}else ts=[]}else de.startsWith('"')&&de.endsWith('"')?ts=de.slice(1,-1):isNaN(Number(de))?ts=de.replace(/"/g,""):ts=Number(de);if(W in P){const Ke=P[W];Ke[Vs]=ts}}}return P},ae=G=>{const P=[],B=(W,Ce)=>W===""||W===null||W===void 0?Ce:W;return P.push("[inner]"),P.push(`version = "${B(G.inner.version,ea.inner.version)}" # 版本号`),P.push("# 请勿修改版本号,除非你知道自己在做什么"),P.push(""),P.push("[nickname] # 现在没用"),P.push(`nickname = "${B(G.nickname.nickname,ea.nickname.nickname)}"`),P.push(""),P.push("[napcat_server] # Napcat连接的ws服务设置"),P.push(`host = "${B(G.napcat_server.host,ea.napcat_server.host)}" # Napcat设定的主机地址`),P.push(`port = ${B(G.napcat_server.port||0,ea.napcat_server.port)} # Napcat设定的端口`),P.push(`token = "${B(G.napcat_server.token,ea.napcat_server.token)}" # Napcat设定的访问令牌,若无则留空`),P.push(`heartbeat_interval = ${B(G.napcat_server.heartbeat_interval||0,ea.napcat_server.heartbeat_interval)} # 与Napcat设置的心跳相同(按秒计)`),P.push(""),P.push("[maibot_server] # 连接麦麦的ws服务设置"),P.push(`host = "${B(G.maibot_server.host,ea.maibot_server.host)}" # 麦麦在.env文件中设置的主机地址,即HOST字段`),P.push(`port = ${B(G.maibot_server.port||0,ea.maibot_server.port)} # 麦麦在.env文件中设置的端口,即PORT字段`),P.push(""),P.push("[chat] # 黑白名单功能"),P.push(`group_list_type = "${B(G.chat.group_list_type,ea.chat.group_list_type)}" # 群组名单类型,可选为:whitelist, blacklist`),P.push(`group_list = [${G.chat.group_list.join(", ")}] # 群组名单`),P.push("# 当group_list_type为whitelist时,只有群组名单中的群组可以聊天"),P.push("# 当group_list_type为blacklist时,群组名单中的任何群组无法聊天"),P.push(`private_list_type = "${B(G.chat.private_list_type,ea.chat.private_list_type)}" # 私聊名单类型,可选为:whitelist, blacklist`),P.push(`private_list = [${G.chat.private_list.join(", ")}] # 私聊名单`),P.push("# 当private_list_type为whitelist时,只有私聊名单中的用户可以聊天"),P.push("# 当private_list_type为blacklist时,私聊名单中的任何用户无法聊天"),P.push(`ban_user_id = [${G.chat.ban_user_id.join(", ")}] # 全局禁止名单(全局禁止名单中的用户无法进行任何聊天)`),P.push(`ban_qq_bot = ${G.chat.ban_qq_bot} # 是否屏蔽QQ官方机器人`),P.push(`enable_poke = ${G.chat.enable_poke} # 是否启用戳一戳功能`),P.push(""),P.push("[voice] # 发送语音设置"),P.push(`use_tts = ${G.voice.use_tts} # 是否使用tts语音(请确保你配置了tts并有对应的adapter)`),P.push(""),P.push("[debug]"),P.push(`level = "${B(G.debug.level,ea.debug.level)}" # 日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)`),P.join(` -`)},fe=G=>{const P=G.target.files?.[0];if(!P)return;const B=new FileReader;B.onload=W=>{try{const Ce=W.target?.result,Me=ie(Ce);d(Me),x(P.name),T({title:"上传成功",description:`已加载配置文件:${P.name}`})}catch(Ce){console.error("解析配置文件失败:",Ce),T({title:"解析失败",description:"配置文件格式错误,请检查文件内容",variant:"destructive"})}},B.readAsText(P)},Ne=()=>{if(!c)return;const G=ae(c),P=new Blob([G],{type:"text/plain;charset=utf-8"}),B=URL.createObjectURL(P),W=document.createElement("a");W.href=B,W.download=h||"config.toml",document.body.appendChild(W),W.click(),document.body.removeChild(W),URL.revokeObjectURL(B),T({title:"下载成功",description:"配置文件已下载,请手动覆盖并重启适配器"})},me=()=>{d(JSON.parse(JSON.stringify(ea))),x("config.toml"),T({title:"已加载默认配置",description:"可以开始编辑配置"})};return e.jsx(ss,{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(Oa,{className:"h-4 w-4 mt-0.5 flex-shrink-0"}),e.jsx("p",{className:"text-sm",children:"适配器配置保存之后使用 WebUI 的重启功能适配器并不会重启,需要手动重启适配器。"})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"工作模式"}),e.jsx(ct,{children:"选择配置文件的管理方式"})]}),e.jsxs(Ts,{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:()=>z("preset"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(dn,{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:()=>z("upload"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(fr,{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:()=>z("path"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(_b,{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(b,{className:"text-sm md:text-base",children:"选择部署方式"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:Object.entries(zu).map(([G,P])=>{const B=P.icon,W=p===G;return e.jsx("div",{className:`border-2 rounded-lg p-3 cursor-pointer transition-all ${W?"border-primary bg-primary/5":"border-muted hover:border-primary/50"}`,onClick:()=>{w(G),_e(G)},children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(B,{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:P.name}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:P.description}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 font-mono break-all",children:P.path})]})]})},G)})})]}),n==="path"&&e.jsxs("div",{className:"space-y-3 pt-2 border-t",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{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(oe,{id:"config-path",value:f,onChange:G=>xe(G.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(N,{onClick:()=>Se(f),disabled:M||!f||!!v,className:"w-full sm:w-auto",children:M?e.jsxs(e.Fragment,{children:[e.jsx(Ct,{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(cl,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsx(ol,{children:n==="preset"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"预设模式:"}),"选择预设的部署方式,配置会自动加载,修改后 1 秒自动保存",S&&" (正在保存...)"]}):n==="upload"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"上传文件模式:"}),"上传配置文件 → 在线编辑 → 下载文件 → 手动覆盖并重启适配器"]}):e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"指定路径模式:"}),"指定配置文件路径后,配置会自动加载,修改后 1 秒自动保存",S&&" (正在保存...)"]})})]}),n==="upload"&&!c&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 w-full",children:[e.jsx("input",{ref:Q,type:"file",accept:".toml",className:"hidden",onChange:fe}),e.jsxs(N,{onClick:()=>Q.current?.click(),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(fr,{className:"mr-2 h-4 w-4"}),"上传配置"]}),e.jsxs(N,{onClick:me,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(Da,{className:"mr-2 h-4 w-4"}),"使用默认配置"]})]}),n==="upload"&&c&&e.jsx("div",{className:"flex gap-2",children:e.jsxs(N,{onClick:Ne,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(rl,{className:"mr-2 h-4 w-4"}),"下载配置"]})}),(n==="preset"||n==="path")&&c&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs(N,{onClick:ye,size:"sm",disabled:S||!!v,className:"w-full sm:w-auto",children:[e.jsx(yr,{className:"mr-2 h-4 w-4"}),S?"保存中...":"立即保存"]}),e.jsxs(N,{onClick:be,size:"sm",variant:"outline",disabled:M,className:"w-full sm:w-auto",children:[e.jsx(Ct,{className:`mr-2 h-4 w-4 ${M?"animate-spin":""}`}),"刷新"]}),n==="path"&&e.jsxs(N,{onClick:se,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(ls,{className:"mr-2 h-4 w-4"}),"清空路径"]})]}),c?e.jsxs(La,{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(wa,{className:"inline-flex w-auto min-w-full sm:grid sm:w-full sm:grid-cols-5",children:[e.jsxs(fs,{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(fs,{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(fs,{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(fs,{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(fs,{value:"debug",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:"调试"})]})}),e.jsx(Ms,{value:"napcat",className:"space-y-4",children:e.jsx(mw,{config:c,onChange:G=>{d(G),ge(G)}})}),e.jsx(Ms,{value:"maibot",className:"space-y-4",children:e.jsx(hw,{config:c,onChange:G=>{d(G),ge(G)}})}),e.jsx(Ms,{value:"chat",className:"space-y-4",children:e.jsx(xw,{config:c,onChange:G=>{d(G),ge(G)}})}),e.jsx(Ms,{value:"voice",className:"space-y-4",children:e.jsx(fw,{config:c,onChange:G=>{d(G),ge(G)}})}),e.jsx(Ms,{value:"debug",className:"space-y-4",children:e.jsx(pw,{config:c,onChange:G=>{d(G),ge(G)}})})]}):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(Da,{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(ps,{open:U,onOpenChange:O,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认切换模式"}),e.jsxs(ds,{children:["切换模式将清空当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-destructive font-medium",children:"请确保已保存重要配置"})]})]}),e.jsxs(cs,{children:[e.jsx(ms,{onClick:()=>{O(!1),V(null)},children:"取消"}),e.jsx(us,{onClick:k,children:"确认切换"})]})]})}),e.jsx(ps,{open:K,onOpenChange:H,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认清空路径"}),e.jsxs(ds,{children:["清空路径将清除当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-muted-foreground text-sm",children:"此操作不会删除配置文件,只是清除界面中的配置"})]})]}),e.jsxs(cs,{children:[e.jsx(ms,{onClick:()=>H(!1),children:"取消"}),e.jsx(us,{onClick:ue,className:"bg-destructive hover:bg-destructive/90",children:"确认清空"})]})]})})]})})}function mw({config:n,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(b,{htmlFor:"napcat-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(oe,{id:"napcat-host",value:n.napcat_server.host,onChange:c=>i({...n,napcat_server:{...n.napcat_server,host:c.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(b,{htmlFor:"napcat-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(oe,{id:"napcat-port",type:"number",value:n.napcat_server.port||"",onChange:c=>i({...n,napcat_server:{...n.napcat_server,port:c.target.value?parseInt(c.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(b,{htmlFor:"napcat-token",className:"text-sm md:text-base",children:"访问令牌(Token)"}),e.jsx(oe,{id:"napcat-token",type:"password",value:n.napcat_server.token,onChange:c=>i({...n,napcat_server:{...n.napcat_server,token:c.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(b,{htmlFor:"napcat-heartbeat",className:"text-sm md:text-base",children:"心跳间隔(秒)"}),e.jsx(oe,{id:"napcat-heartbeat",type:"number",value:n.napcat_server.heartbeat_interval||"",onChange:c=>i({...n,napcat_server:{...n.napcat_server,heartbeat_interval:c.target.value?parseInt(c.target.value):0}}),placeholder:"30",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"与 Napcat 设置的心跳间隔保持一致(留空使用默认值 30)"})]})]})]})})}function hw({config:n,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(b,{htmlFor:"maibot-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(oe,{id:"maibot-host",value:n.maibot_server.host,onChange:c=>i({...n,maibot_server:{...n.maibot_server,host:c.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(b,{htmlFor:"maibot-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(oe,{id:"maibot-port",type:"number",value:n.maibot_server.port||"",onChange:c=>i({...n,maibot_server:{...n.maibot_server,port:c.target.value?parseInt(c.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 xw({config:n,onChange:i}){const c=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],i(f)},d=(x,f)=>{const j={...n};x==="group"?j.chat.group_list=j.chat.group_list.filter((p,w)=>w!==f):x==="private"?j.chat.private_list=j.chat.private_list.filter((p,w)=>w!==f):j.chat.ban_user_id=j.chat.ban_user_id.filter((p,w)=>w!==f),i(j)},h=(x,f,j)=>{const p={...n};x==="group"?p.chat.group_list[f]=j:x==="private"?p.chat.private_list[f]=j:p.chat.ban_user_id[f]=j,i(p)};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(b,{className:"text-sm md:text-base",children:"群组名单类型"}),e.jsxs(He,{value:n.chat.group_list_type,onValueChange:x=>i({...n,chat:{...n.chat,group_list_type:x}}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{className:"text-sm md:text-base",children:"群组列表"}),e.jsxs(N,{onClick:()=>c("group"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Da,{className:"mr-1 h-4 w-4"}),"添加群号"]})]}),n.chat.group_list.map((x,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(oe,{type:"number",value:x,onChange:j=>h("group",f,parseInt(j.target.value)||0),placeholder:"输入群号",className:"text-sm md:text-base"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除群号 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{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(b,{className:"text-sm md:text-base",children:"私聊名单类型"}),e.jsxs(He,{value:n.chat.private_list_type,onValueChange:x=>i({...n,chat:{...n.chat,private_list_type:x}}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{className:"text-sm md:text-base",children:"私聊列表"}),e.jsxs(N,{onClick:()=>c("private"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Da,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),n.chat.private_list.map((x,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(oe,{type:"number",value:x,onChange:j=>h("private",f,parseInt(j.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要删除用户 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{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(b,{className:"text-sm md:text-base",children:"全局禁止名单"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"名单中的用户无法进行任何聊天"})]}),e.jsxs(N,{onClick:()=>c("ban"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Da,{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(oe,{type:"number",value:x,onChange:j=>h("ban",f,parseInt(j.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ls,{className:"h-4 w-4"})})}),e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:["确定要从全局禁止名单中删除用户 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{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(b,{className:"text-sm md:text-base",children:"屏蔽QQ官方机器人"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否屏蔽来自QQ官方机器人的消息"})]}),e.jsx(Xe,{checked:n.chat.ban_qq_bot,onCheckedChange:x=>i({...n,chat:{...n.chat,ban_qq_bot:x}})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(b,{className:"text-sm md:text-base",children:"启用戳一戳功能"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否响应戳一戳消息"})]}),e.jsx(Xe,{checked:n.chat.enable_poke,onCheckedChange:x=>i({...n,chat:{...n.chat,enable_poke:x}})})]})]})]})})}function fw({config:n,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(b,{className:"text-sm md:text-base",children:"使用 TTS 语音"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"请确保已配置 TTS 并有对应的适配器"})]}),e.jsx(Xe,{checked:n.voice.use_tts,onCheckedChange:c=>i({...n,voice:{use_tts:c}})})]})]})})}function pw({config:n,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(b,{className:"text-sm md:text-base",children:"日志等级"}),e.jsxs(He,{value:n.debug.level,onValueChange:c=>i({...n,debug:{level:c}}),children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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 gw=["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"],jw=/^(aria-|data-)/,Og=n=>Object.fromEntries(Object.entries(n).filter(([i])=>jw.test(i)||gw.includes(i)));function vw(n,i){const c=Og(n);return Object.keys(n).some(d=>!Object.hasOwn(c,d)&&n[d]!==i[d])}class Nw extends u.Component{container;plugin;componentDidMount(){this.installPlugin()}componentDidUpdate(i){if(i.uppy!==this.props.uppy)this.uninstallPlugin(i),this.installPlugin();else if(vw(this.props,i)){const{uppy:c,...d}={...this.props,target:this.container};this.plugin.setOptions(d)}}componentWillUnmount(){this.uninstallPlugin()}installPlugin(){const{uppy:i,...c}={id:"Dashboard",...this.props,inline:!0,target:this.container};i.use(ny,c),this.plugin=i.getPlugin(c.id)}uninstallPlugin(i=this.props){const{uppy:c}=i;c.removePlugin(this.plugin)}render(){return u.createElement("div",{className:"uppy-Container",ref:i=>{this.container=i},...Og(this.props)})}}function bw({src:n,alt:i="表情包",className:c,maxRetries:d=5,retryInterval:h=1500}){const[x,f]=u.useState("loading"),[j,p]=u.useState(0),[w,v]=u.useState(null),y=u.useCallback(async()=>{try{const S=await fetch(n,{credentials:"include"});if(S.status===202){f("generating"),j{p(F=>F+1)},h):f("error");return}if(!S.ok){f("error");return}const C=await S.blob(),M=URL.createObjectURL(C);v(M),f("loaded")}catch(S){console.error("加载缩略图失败:",S),f("error")}},[n,j,d,h]);return u.useEffect(()=>{f("loading"),p(0),v(null)},[n]),u.useEffect(()=>{y()},[y]),u.useEffect(()=>()=>{w&&URL.revokeObjectURL(w)},[w]),x==="loading"||x==="generating"?e.jsx(gg,{className:$("w-full h-full",c)}):x==="error"||!w?e.jsx("div",{className:$("w-full h-full flex items-center justify-center bg-muted",c),children:e.jsx(dg,{className:"h-8 w-8 text-muted-foreground"})}):e.jsx("img",{src:w,alt:i,className:$("w-full h-full object-contain",c)})}function yw({content:n,className:i=""}){return e.jsx("div",{className:`prose prose-sm dark:prose-invert max-w-none ${i}`,children:e.jsx(ry,{remarkPlugins:[oy,dy],rehypePlugins:[cy],components:{code({inline:c,className:d,children:h,...x}){return c?e.jsx("code",{className:"bg-muted px-1.5 py-0.5 rounded text-sm font-mono",...x,children:h}):e.jsx("code",{className:`${d} block bg-muted p-4 rounded-lg overflow-x-auto`,...x,children:h})},table({children:c,...d}){return e.jsx("div",{className:"overflow-x-auto",children:e.jsx("table",{className:"border-collapse border border-border",...d,children:c})})},th({children:c,...d}){return e.jsx("th",{className:"border border-border bg-muted px-4 py-2 text-left font-semibold",...d,children:c})},td({children:c,...d}){return e.jsx("td",{className:"border border-border px-4 py-2",...d,children:c})},a({children:c,...d}){return e.jsx("a",{className:"text-primary hover:underline",target:"_blank",rel:"noopener noreferrer",...d,children:c})},blockquote({children:c,...d}){return e.jsx("blockquote",{className:"border-l-4 border-primary pl-4 italic text-muted-foreground",...d,children:c})},h1({children:c,...d}){return e.jsx("h1",{className:"text-3xl font-bold mt-6 mb-4",...d,children:c})},h2({children:c,...d}){return e.jsx("h2",{className:"text-2xl font-bold mt-5 mb-3",...d,children:c})},h3({children:c,...d}){return e.jsx("h3",{className:"text-xl font-bold mt-4 mb-2",...d,children:c})},h4({children:c,...d}){return e.jsx("h4",{className:"text-lg font-semibold mt-3 mb-2",...d,children:c})},ul({children:c,...d}){return e.jsx("ul",{className:"list-disc list-inside space-y-1 my-2",...d,children:c})},ol({children:c,...d}){return e.jsx("ol",{className:"list-decimal list-inside space-y-1 my-2",...d,children:c})},p({children:c,...d}){return e.jsx("p",{className:"my-2 leading-relaxed",...d,children:c})},hr({...c}){return e.jsx("hr",{className:"my-4 border-border",...c})}},children:n})})}function ww({children:n,className:i}){return e.jsx(yw,{content:n,className:i})}const pa="/api/webui/emoji";async function _w(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.is_registered!==void 0&&i.append("is_registered",n.is_registered.toString()),n.is_banned!==void 0&&i.append("is_banned",n.is_banned.toString()),n.format&&i.append("format",n.format),n.sort_by&&i.append("sort_by",n.sort_by),n.sort_order&&i.append("sort_order",n.sort_order);const c=await Te(`${pa}/list?${i}`,{});if(!c.ok)throw new Error(`获取表情包列表失败: ${c.statusText}`);return c.json()}async function Sw(n){const i=await Te(`${pa}/${n}`,{});if(!i.ok)throw new Error(`获取表情包详情失败: ${i.statusText}`);return i.json()}async function Cw(n,i){const c=await Te(`${pa}/${n}`,{method:"PATCH",body:JSON.stringify(i)});if(!c.ok)throw new Error(`更新表情包失败: ${c.statusText}`);return c.json()}async function kw(n){const i=await Te(`${pa}/${n}`,{method:"DELETE"});if(!i.ok)throw new Error(`删除表情包失败: ${i.statusText}`);return i.json()}async function Tw(){const n=await Te(`${pa}/stats/summary`,{});if(!n.ok)throw new Error(`获取统计数据失败: ${n.statusText}`);return n.json()}async function Ew(n){const i=await Te(`${pa}/${n}/register`,{method:"POST"});if(!i.ok)throw new Error(`注册表情包失败: ${i.statusText}`);return i.json()}async function zw(n){const i=await Te(`${pa}/${n}/ban`,{method:"POST"});if(!i.ok)throw new Error(`封禁表情包失败: ${i.statusText}`);return i.json()}function Aw(n,i=!1){return i?`${pa}/${n}/thumbnail?original=true`:`${pa}/${n}/thumbnail`}function Mw(n){return`${pa}/${n}/thumbnail?original=true`}async function Dw(n){const i=await Te(`${pa}/batch/delete`,{method:"POST",body:JSON.stringify({emoji_ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除失败")}return i.json()}function Ow(){return`${pa}/upload`}function Rw(){const[n,i]=u.useState([]),[c,d]=u.useState(null),[h,x]=u.useState(!1),[f,j]=u.useState(1),[p,w]=u.useState(0),[v,y]=u.useState(20),[S,C]=u.useState("all"),[M,F]=u.useState("all"),[U,O]=u.useState("all"),[K,H]=u.useState("usage_count"),[A,V]=u.useState("desc"),[Q,T]=u.useState(null),[D,ne]=u.useState(!1),[xe,_e]=u.useState(!1),[Se,ge]=u.useState(!1),[ye,be]=u.useState(new Set),[z,X]=u.useState(!1),[k,se]=u.useState(""),[_,ue]=u.useState("medium"),[ie,ae]=u.useState(!1),{toast:fe}=Gs(),Ne=u.useCallback(async()=>{try{x(!0);const de=await _w({page:f,page_size:v,is_registered:S==="all"?void 0:S==="registered",is_banned:M==="all"?void 0:M==="banned",format:U==="all"?void 0:U,sort_by:K,sort_order:A});i(de.data),w(de.total)}catch(de){const Ee=de instanceof Error?de.message:"加载表情包列表失败";fe({title:"错误",description:Ee,variant:"destructive"})}finally{x(!1)}},[f,v,S,M,U,K,A,fe]),me=async()=>{try{const de=await Tw();d(de.data)}catch(de){console.error("加载统计数据失败:",de)}};u.useEffect(()=>{Ne()},[Ne]),u.useEffect(()=>{me()},[]);const G=async de=>{try{const Ee=await Sw(de.id);T(Ee.data),ne(!0)}catch(Ee){const ts=Ee instanceof Error?Ee.message:"加载详情失败";fe({title:"错误",description:ts,variant:"destructive"})}},P=de=>{T(de),_e(!0)},B=de=>{T(de),ge(!0)},W=async()=>{if(Q)try{await kw(Q.id),fe({title:"成功",description:"表情包已删除"}),ge(!1),T(null),Ne(),me()}catch(de){const Ee=de instanceof Error?de.message:"删除失败";fe({title:"错误",description:Ee,variant:"destructive"})}},Ce=async de=>{try{await Ew(de.id),fe({title:"成功",description:"表情包已注册"}),Ne(),me()}catch(Ee){const ts=Ee instanceof Error?Ee.message:"注册失败";fe({title:"错误",description:ts,variant:"destructive"})}},Me=async de=>{try{await zw(de.id),fe({title:"成功",description:"表情包已封禁"}),Ne(),me()}catch(Ee){const ts=Ee instanceof Error?Ee.message:"封禁失败";fe({title:"错误",description:ts,variant:"destructive"})}},re=de=>{const Ee=new Set(ye);Ee.has(de)?Ee.delete(de):Ee.add(de),be(Ee)},De=async()=>{try{const de=await Dw(Array.from(ye));fe({title:"批量删除完成",description:de.message}),be(new Set),X(!1),Ne(),me()}catch(de){fe({title:"批量删除失败",description:de instanceof Error?de.message:"批量删除失败",variant:"destructive"})}},Vs=()=>{const de=parseInt(k),Ee=Math.ceil(p/v);de>=1&&de<=Ee?(j(de),se("")):fe({title:"无效的页码",description:`请输入1-${Ee}之间的页码`,variant:"destructive"})},Qs=c?.formats?Object.keys(c.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(N,{onClick:()=>ae(!0),className:"gap-2",children:[e.jsx(fr,{className:"h-4 w-4"}),"上传表情包"]})]}),e.jsx(ss,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[c&&e.jsxs("div",{className:"grid gap-4 grid-cols-2 lg:grid-cols-4",children:[e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"总数"}),e.jsx(ws,{className:"text-2xl",children:c.total})]})}),e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"已注册"}),e.jsx(ws,{className:"text-2xl text-green-600",children:c.registered})]})}),e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"已封禁"}),e.jsx(ws,{className:"text-2xl text-red-600",children:c.banned})]})}),e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"未注册"}),e.jsx(ws,{className:"text-2xl text-gray-600",children:c.unregistered})]})})]}),e.jsxs(Ze,{children:[e.jsx(ys,{children:e.jsxs(ws,{className:"flex items-center gap-2",children:[e.jsx(Mu,{className:"h-5 w-5"}),"筛选和排序"]})}),e.jsxs(Ts,{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(b,{children:"排序方式"}),e.jsxs(He,{value:`${K}-${A}`,onValueChange:de=>{const[Ee,ts]=de.split("-");H(Ee),V(ts),j(1)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{children:"注册状态"}),e.jsxs(He,{value:S,onValueChange:de=>{C(de),j(1)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{children:"封禁状态"}),e.jsxs(He,{value:M,onValueChange:de=>{F(de),j(1)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{children:"格式"}),e.jsxs(He,{value:U,onValueChange:de=>{O(de),j(1)},children:[e.jsx(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"all",children:"全部"}),Qs.map(de=>e.jsxs(le,{value:de,children:[de.toUpperCase()," (",c?.formats[de],")"]},de))]})]})]})]}),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:[ye.size>0&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:["已选择 ",ye.size," 个表情包"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{className:"text-sm whitespace-nowrap",children:"卡片大小"}),e.jsxs(He,{value:_,onValueChange:de=>ue(de),children:[e.jsx(Le,{className:"w-24",children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{htmlFor:"emoji-page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(He,{value:v.toString(),onValueChange:de=>{y(parseInt(de)),j(1),be(new Set)},children:[e.jsx(Le,{id:"emoji-page-size",className:"w-20",children:e.jsx(qe,{})}),e.jsxs(Ue,{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"})]})]}),ye.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>be(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:()=>X(!0),children:[e.jsx(ls,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]}),e.jsx("div",{className:"flex justify-end pt-4 border-t",children:e.jsxs(N,{variant:"outline",size:"sm",onClick:Ne,disabled:h,children:[e.jsx(Ct,{className:`h-4 w-4 mr-2 ${h?"animate-spin":""}`}),"刷新"]})})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"表情包列表"}),e.jsxs(ct,{children:["共 ",p," 个表情包,当前第 ",f," 页"]})]}),e.jsxs(Ts,{children:[n.length===0?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:"暂无数据"}):e.jsx("div",{className:`grid gap-3 ${_==="small"?"grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10":_==="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(de=>e.jsxs("div",{className:`group relative rounded-lg border bg-card overflow-hidden hover:ring-2 hover:ring-primary transition-all cursor-pointer ${ye.has(de.id)?"ring-2 ring-primary bg-primary/5":""}`,onClick:()=>re(de.id),children:[e.jsx("div",{className:`absolute top-1 left-1 z-10 transition-opacity ${ye.has(de.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 ${ye.has(de.id)?"bg-primary border-primary text-primary-foreground":"bg-background/80 border-muted-foreground/50"}`,children:ye.has(de.id)&&e.jsx(fa,{className:"h-3 w-3"})})}),e.jsxs("div",{className:"absolute top-1 right-1 z-10 flex flex-col gap-0.5",children:[de.is_registered&&e.jsx(Ye,{variant:"default",className:"bg-green-600 text-[10px] px-1 py-0",children:"已注册"}),de.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 ${_==="small"?"p-1":_==="medium"?"p-2":"p-3"}`,children:e.jsx(bw,{src:Aw(de.id),alt:"表情包"})}),e.jsxs("div",{className:`border-t bg-card ${_==="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:de.format.toUpperCase()}),e.jsxs("span",{className:"font-mono",children:[de.usage_count,"次"]})]}),e.jsxs("div",{className:`flex gap-1 justify-center opacity-0 group-hover:opacity-100 transition-opacity ${_==="small"?"flex-wrap":""}`,children:[e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:Ee=>{Ee.stopPropagation(),P(de)},title:"编辑",children:e.jsx(mn,{className:"h-3 w-3"})}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:Ee=>{Ee.stopPropagation(),G(de)},title:"详情",children:e.jsx(Ra,{className:"h-3 w-3"})}),!de.is_registered&&e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6 text-green-600 hover:text-green-700",onClick:Ee=>{Ee.stopPropagation(),Ce(de)},title:"注册",children:e.jsx(fa,{className:"h-3 w-3"})}),!de.is_banned&&e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6 text-orange-600 hover:text-orange-700",onClick:Ee=>{Ee.stopPropagation(),Me(de)},title:"封禁",children:e.jsx(Sb,{className:"h-3 w-3"})}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6 text-red-600 hover:text-red-700",onClick:Ee=>{Ee.stopPropagation(),B(de)},title:"删除",children:e.jsx(ls,{className:"h-3 w-3"})})]})]})]},de.id))}),p>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)*v+1," 到"," ",Math.min(f*v,p)," 条,共 ",p," 条"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(de=>Math.max(1,de-1)),disabled:f===1,children:[e.jsx(Hl,{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(oe,{type:"number",value:k,onChange:de=>se(de.target.value),onKeyDown:de=>de.key==="Enter"&&Vs(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(p/v)}),e.jsx(N,{variant:"outline",size:"sm",onClick:Vs,disabled:!k,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(de=>de+1),disabled:f>=Math.ceil(p/v),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(p/v)),disabled:f>=Math.ceil(p/v),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]}),e.jsx(Lw,{emoji:Q,open:D,onOpenChange:ne}),e.jsx(Uw,{emoji:Q,open:xe,onOpenChange:_e,onSuccess:()=>{Ne(),me()}}),e.jsx(Bw,{open:ie,onOpenChange:ae,onSuccess:()=>{Ne(),me()}})]})}),e.jsx(ps,{open:z,onOpenChange:X,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认批量删除"}),e.jsxs(ds,{children:["你确定要删除选中的 ",ye.size," 个表情包吗?此操作不可撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:De,children:"确认删除"})]})]})}),e.jsx($s,{open:Se,onOpenChange:ge,children:e.jsxs(Bs,{children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"确认删除"}),e.jsx(Is,{children:"确定要删除这个表情包吗?此操作无法撤销。"})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>ge(!1),children:"取消"}),e.jsx(N,{variant:"destructive",onClick:W,children:"删除"})]})]})})]})}function Lw({emoji:n,open:i,onOpenChange:c}){if(!n)return null;const d=h=>h?new Date(h*1e3).toLocaleString("zh-CN"):"-";return e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[90vh]",children:[e.jsx(Hs,{children:e.jsx(qs,{children:"表情包详情"})}),e.jsx(ss,{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:Mw(n.id),alt:n.description||"表情包",className:"w-full h-full object-cover",onError:h=>{const x=h.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(b,{className:"text-muted-foreground",children:"ID"}),e.jsx("div",{className:"mt-1 font-mono",children:n.id})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"格式"}),e.jsx("div",{className:"mt-1",children:e.jsx(Ye,{variant:"outline",children:n.format.toUpperCase()})})]})]}),e.jsxs("div",{children:[e.jsx(b,{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(b,{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(b,{className:"text-muted-foreground",children:"描述"}),n.description?e.jsx("div",{className:"mt-1 rounded-lg border bg-muted/50 p-3",children:e.jsx(ww,{className:"prose-sm",children:n.description})}):e.jsx("div",{className:"mt-1 text-sm text-muted-foreground",children:"-"})]}),e.jsxs("div",{children:[e.jsx(b,{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(b,{className:"text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"mt-2 flex gap-2",children:[n.is_registered&&e.jsx(Ye,{variant:"default",className:"bg-green-600",children:"已注册"}),n.is_banned&&e.jsx(Ye,{variant:"destructive",children:"已封禁"}),!n.is_registered&&!n.is_banned&&e.jsx(Ye,{variant:"outline",children:"未注册"})]})]}),e.jsxs("div",{children:[e.jsx(b,{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(b,{className:"text-muted-foreground",children:"记录时间"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.record_time)})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"注册时间"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.register_time)})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"最后使用"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.last_used_time)})]})]})})]})})}function Uw({emoji:n,open:i,onOpenChange:c,onSuccess:d}){const[h,x]=u.useState(""),[f,j]=u.useState(!1),[p,w]=u.useState(!1),[v,y]=u.useState(!1),{toast:S}=Gs();u.useEffect(()=>{n&&(x(n.emotion||""),j(n.is_registered),w(n.is_banned))},[n]);const C=async()=>{if(n)try{y(!0);const M=h.split(/[,,]/).map(F=>F.trim()).filter(Boolean).join(",");await Cw(n.id,{emotion:M||void 0,is_registered:f,is_banned:p}),S({title:"成功",description:"表情包信息已更新"}),c(!1),d()}catch(M){const F=M instanceof Error?M.message:"保存失败";S({title:"错误",description:F,variant:"destructive"})}finally{y(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"编辑表情包"}),e.jsx(Is,{children:"修改表情包的情绪和状态信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(b,{children:"情绪"}),e.jsx(Fs,{value:h,onChange:M=>x(M.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:f,onCheckedChange:M=>{M===!0?(j(!0),w(!1)):j(!1)}}),e.jsx(b,{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:p,onCheckedChange:M=>{M===!0?(w(!0),j(!1)):w(!1)}}),e.jsx(b,{htmlFor:"is_banned",className:"cursor-pointer",children:"已封禁"})]})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:C,disabled:v,children:v?"保存中...":"保存"})]})]})}):null}function Bw({open:n,onOpenChange:i,onSuccess:c}){const[d,h]=u.useState("select"),[x,f]=u.useState([]),[j,p]=u.useState(null),[w,v]=u.useState(!1),{toast:y}=Gs(),S=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 Q=()=>{const T=S.getFiles();if(T.length===0)return;const D=T.map(ne=>({id:ne.id,name:ne.name,previewUrl:ne.preview||URL.createObjectURL(ne.data),emotion:"",description:"",isRegistered:!0,file:ne.data}));f(D),T.length===1?(p(D[0].id),h("edit-single")):h("edit-multiple")};return S.on("upload",Q),()=>{S.off("upload",Q)}},[S]),u.useEffect(()=>{n||(S.cancelAll(),h("select"),f([]),p(null),v(!1))},[n,S]);const C=u.useCallback((Q,T)=>{f(D=>D.map(ne=>ne.id===Q?{...ne,...T}:ne))},[]),M=u.useCallback(Q=>Q.emotion.trim().length>0,[]),F=u.useMemo(()=>x.length>0&&x.every(M),[x,M]),U=u.useMemo(()=>x.find(Q=>Q.id===j)||null,[x,j]),O=u.useCallback(()=>{(d==="edit-single"||d==="edit-multiple")&&(h("select"),f([]),p(null))},[d]),K=u.useCallback(async()=>{if(!F){y({title:"请填写必填项",description:"每个表情包的情感标签都是必填的",variant:"destructive"});return}v(!0);const Q=localStorage.getItem("access-token")||"";let T=0,D=0;try{for(const ne of x){const xe=new FormData;xe.append("file",ne.file),xe.append("emotion",ne.emotion),xe.append("description",ne.description),xe.append("is_registered",ne.isRegistered.toString());try{(await fetch(Ow(),{method:"POST",headers:{Authorization:`Bearer ${Q}`},body:xe})).ok?T++:D++}catch{D++}}D===0?(y({title:"上传成功",description:`成功上传 ${T} 个表情包`}),i(!1),c()):(y({title:"部分上传失败",description:`成功 ${T} 个,失败 ${D} 个`,variant:"destructive"}),c())}finally{v(!1)}},[F,x,y,i,c]),H=()=>e.jsx("div",{className:"space-y-4",children:e.jsx("div",{className:"border rounded-lg overflow-hidden w-full",children:e.jsx(Nw,{uppy:S,proudlyDisplayPoweredByUppy:!1,hideProgressDetails:!0,height:350,width:"100%",theme:"auto",note:"支持 JPG、PNG、GIF、WebP 格式,最多 20 个文件"})})}),A=()=>{const Q=x[0];return Q?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs(N,{variant:"ghost",size:"sm",onClick:O,children:[e.jsx(ii,{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:Q.previewUrl,alt:Q.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:Q.name})]}),e.jsxs("div",{className:"flex-1 space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"single-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(oe,{id:"single-emotion",value:Q.emotion,onChange:T=>C(Q.id,{emotion:T.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:Q.emotion.trim()?"":"border-destructive"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"用于情感匹配,多个标签用逗号分隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"single-description",children:"描述"}),e.jsx(oe,{id:"single-description",value:Q.description,onChange:T=>C(Q.id,{description:T.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"single-is-registered",checked:Q.isRegistered,onCheckedChange:T=>C(Q.id,{isRegistered:T===!0})}),e.jsx(b,{htmlFor:"single-is-registered",className:"cursor-pointer",children:"上传后立即注册(可被麦麦使用)"})]})]})]}),e.jsx(at,{children:e.jsx(N,{onClick:K,disabled:!F||w,children:w?"上传中...":"上传"})})]}):null},V=()=>{const Q=x.filter(M).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(N,{variant:"ghost",size:"sm",onClick:O,children:[e.jsx(ii,{className:"h-4 w-4 mr-1"}),"返回"]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["编辑表情包信息(",Q,"/",T," 已完成)"]})]}),e.jsx(Ye,{variant:F?"default":"secondary",children:F?e.jsxs(e.Fragment,{children:[e.jsx(sa,{className:"h-3 w-3 mr-1"}),"全部完成"]}):e.jsxs(e.Fragment,{children:[e.jsx(dl,{className:"h-3 w-3 mr-1"}),"未完成"]})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(ss,{className:"h-[350px] pr-2",children:e.jsx("div",{className:"space-y-2",children:x.map(D=>{const ne=M(D),xe=j===D.id;return e.jsxs("div",{onClick:()=>p(D.id),className:` +3.某句话如果已经被回复过,不要重复回复`}),[O,Y]=u.useState({emoji_chance:.4,max_reg_num:40,do_replace:!0,check_interval:10,steal_emoji:!0,content_filtration:!1,filtration_prompt:"符合公序良俗"}),[L,R]=u.useState({enable_tool:!0,enable_mood:!1,mood_update_threshold:1,emotion_style:"情绪较为稳定,但遇遇特定事件的时候起伏较大",all_global:!0}),[H,D]=u.useState({api_key:""}),[C,$]=u.useState(!1),[G,T]=u.useState(""),M=[{id:"bot-basic",title:"Bot基础",description:"配置机器人的基本信息",icon:cr},{id:"personality",title:"人格配置",description:"定义机器人的性格和说话风格",icon:Wc},{id:"emoji",title:"表情包",description:"配置表情包相关设置",icon:$u},{id:"other",title:"其他设置",description:"工具、情绪系统等配置",icon:oi},{id:"siliconflow",title:"API配置",description:"配置硅基流动API密钥",icon:ug}],ne=(c+1)/M.length*100;u.useEffect(()=>{(async()=>{try{w(!0);const[K,E,se,_,me]=await Promise.all([f0(),p0(),g0(),j0(),v0()]);y(K),k(E),Y(se),R(_),D(me)}catch(K){i({title:"加载配置失败",description:K instanceof Error?K.message:"无法加载现有配置,将使用默认值",variant:"destructive"})}finally{w(!1)}})()},[i]);const fe=async()=>{j(!0);try{switch(c){case 0:await N0(v);break;case 1:await b0(S);break;case 2:await y0(O);break;case 3:await w0(L);break;case 4:await _0(H);break}return i({title:"保存成功",description:`${M[c].title}配置已保存`}),!0}catch(A){return i({title:"保存失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"}),!1}finally{j(!1)}},_e=async()=>{await fe()&&c{c>0&&d(c-1)},je=async()=>{f(!0),$(!0);try{if(T("正在保存API配置..."),!await fe()){f(!1),$(!1);return}T("正在完成初始化..."),await rp(),T("正在重启麦麦..."),await lo(),i({title:"配置完成",description:"麦麦正在重启以应用新配置..."}),T("等待麦麦重启完成...");const K=60;let E=0,se=!1;for(;EsetTimeout(_,1e3));try{(await S0()).running&&(se=!0,T("重启成功!正在跳转..."))}catch{E++}}if(!se)throw new Error("重启超时,请手动检查麦麦状态");setTimeout(()=>{n({to:"/"})},1e3)}catch(A){$(!1),i({title:"配置失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}finally{f(!1)}},ye=async()=>{try{await rp(),n({to:"/"})}catch(A){i({title:"跳过失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}},be=()=>{switch(c){case 0:return e.jsx(d0,{config:v,onChange:y});case 1:return e.jsx(u0,{config:S,onChange:k});case 2:return e.jsx(m0,{config:O,onChange:Y});case 3:return e.jsx(h0,{config:L,onChange:R});case 4:return e.jsx(x0,{config:H,onChange:D});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:[C&&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(kt,{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:G})]}),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"})]}),p?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(Nb,{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:["让我们一起完成 ",Ju," 的初始配置"]})]}),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:["步骤 ",c+1," / ",M.length]}),e.jsxs("span",{className:"font-medium text-primary",children:[Math.round(ne),"%"]})]}),e.jsx(wr,{value:ne,className:"h-2"})]}),e.jsx("div",{className:"mb-6 md:mb-8 flex justify-between",children:M.map((A,K)=>{const E=A.icon;return e.jsxs("div",{className:X("flex flex-1 flex-col items-center gap-1 md:gap-2",Kn({to:"/"}),className:"gap-2 w-full sm:w-auto",children:[e.jsx(ao,{className:"h-4 w-4"}),"返回首页"]}),e.jsxs(N,{size:"lg",variant:"outline",onClick:()=>window.history.back(),className:"gap-2 w-full sm:w-auto",children:[e.jsx(ii,{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 Be=lb,He=nb,Le=u.forwardRef(({className:n,children:i,...c},d)=>e.jsxs(Xp,{ref:d,className:X("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),...c,children:[i,e.jsx(WN,{asChild:!0,children:e.jsx(Bl,{className:"h-4 w-4 opacity-50"})})]}));Le.displayName=Xp.displayName;const Ag=u.forwardRef(({className:n,...i},c)=>e.jsx(Kp,{ref:c,className:X("flex cursor-default items-center justify-center py-1",n),...i,children:e.jsx(pr,{className:"h-4 w-4"})}));Ag.displayName=Kp.displayName;const Mg=u.forwardRef(({className:n,...i},c)=>e.jsx(Jp,{ref:c,className:X("flex cursor-default items-center justify-center py-1",n),...i,children:e.jsx(Bl,{className:"h-4 w-4"})}));Mg.displayName=Jp.displayName;const Ue=u.forwardRef(({className:n,children:i,position:c="popper",...d},h)=>e.jsx(eb,{children:e.jsxs(Zp,{ref:h,className:X("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]",c==="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:c,...d,children:[e.jsx(Ag,{}),e.jsx(sb,{className:X("p-1",c==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:i}),e.jsx(Mg,{})]})}));Ue.displayName=Zp.displayName;const k0=u.forwardRef(({className:n,...i},c)=>e.jsx(Ip,{ref:c,className:X("px-2 py-1.5 text-sm font-semibold",n),...i}));k0.displayName=Ip.displayName;const te=u.forwardRef(({className:n,children:i,...c},d)=>e.jsxs(Pp,{ref:d,className:X("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),...c,children:[e.jsx("span",{className:"absolute right-2 flex h-3.5 w-3.5 items-center justify-center",children:e.jsx(tb,{children:e.jsx($t,{className:"h-4 w-4"})})}),e.jsx(ab,{children:i})]}));te.displayName=Pp.displayName;const T0=u.forwardRef(({className:n,...i},c)=>e.jsx(Wp,{ref:c,className:X("-mx-1 my-1 h-px bg-muted",n),...i}));T0.displayName=Wp.displayName;const Ua=RN,Ba=LN,ka=u.forwardRef(({className:n,align:i="center",sideOffset:c=4,...d},h)=>e.jsx(ON,{children:e.jsx(Bp,{ref:h,align:i,sideOffset:c,className:X("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=Bp.displayName;const ql="/api/webui/config";async function cp(){const i=await(await Te(`${ql}/bot`)).json();if(!i.success)throw new Error("获取配置数据失败");return i.config}async function ni(){const i=await(await Te(`${ql}/model`)).json();if(!i.success)throw new Error("获取模型配置数据失败");return i.config}async function op(n){const c=await(await Te(`${ql}/bot`,{method:"POST",body:JSON.stringify(n)})).json();if(!c.success)throw new Error(c.message||"保存配置失败")}async function E0(){const i=await(await Te(`${ql}/bot/raw`)).json();if(!i.success)throw new Error("获取配置源代码失败");return i.content}async function z0(n){const c=await(await Te(`${ql}/bot/raw`,{method:"POST",body:JSON.stringify({raw_content:n})})).json();if(!c.success)throw new Error(c.message||"保存配置失败")}async function to(n){const c=await(await Te(`${ql}/model`,{method:"POST",body:JSON.stringify(n)})).json();if(!c.success)throw new Error(c.message||"保存配置失败")}async function A0(n,i){const d=await(await Te(`${ql}/bot/section/${n}`,{method:"POST",body:JSON.stringify(i)})).json();if(!d.success)throw new Error(d.message||`保存配置节 ${n} 失败`)}async function qu(n,i){const d=await(await Te(`${ql}/model/section/${n}`,{method:"POST",body:JSON.stringify(i)})).json();if(!d.success)throw new Error(d.message||`保存配置节 ${n} 失败`)}async function M0(n,i="openai",c="/models"){const d=new URLSearchParams({provider_name:n,parser:i,endpoint:c}),h=await Te(`/api/webui/models/list?${d}`);if(!h.ok){const x=await h.json().catch(()=>({}));throw new Error(x.detail||`获取模型列表失败 (${h.status})`)}const f=await h.json();if(!f.success)throw new Error("获取模型列表失败");return f.models}async function D0(n){const i=new URLSearchParams({provider_name:n}),c=await Te(`/api/webui/models/test-connection-by-name?${i}`,{method:"POST"});if(!c.ok){const d=await c.json().catch(()=>({}));throw new Error(d.detail||`测试连接失败 (${c.status})`)}return await c.json()}const O0=ci("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"}}),cl=u.forwardRef(({className:n,variant:i,...c},d)=>e.jsx("div",{ref:d,role:"alert",className:X(O0({variant:i}),n),...c}));cl.displayName="Alert";const R0=u.forwardRef(({className:n,...i},c)=>e.jsx("h5",{ref:c,className:X("mb-1 font-medium leading-none tracking-tight",n),...i}));R0.displayName="AlertTitle";const ol=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{ref:c,className:X("text-sm [&_p]:leading-relaxed",n),...i}));ol.displayName="AlertDescription";function Pu({onRestartComplete:n,onRestartFailed:i}){const[c,d]=u.useState(0),[h,f]=u.useState("restarting"),[x,j]=u.useState(0),[p,w]=u.useState(0);u.useEffect(()=>{const S=setInterval(()=>{d(Y=>Y>=90?Y:Y+1)},200),k=setInterval(()=>{j(Y=>Y+1)},1e3),O=setTimeout(()=>{f("checking"),v()},3e3);return()=>{clearInterval(S),clearInterval(k),clearTimeout(O)}},[]);const v=()=>{const k=async()=>{try{if(w(Y=>Y+1),(await fetch("/api/webui/system/status",{method:"GET",headers:{"Content-Type":"application/json"},signal:AbortSignal.timeout(3e3)})).ok)d(100),f("success"),setTimeout(()=>{n?.()},1500);else throw new Error("Status check failed")}catch{p<60?setTimeout(k,2e3):(f("failed"),i?.())}};k()},y=S=>{const k=Math.floor(S/60),O=S%60;return`${k}:${O.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:[h==="restarting"&&e.jsxs(e.Fragment,{children:[e.jsx(kt,{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:"请稍候,麦麦正在重启中..."})]}),h==="checking"&&e.jsxs(e.Fragment,{children:[e.jsx(kt,{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:["等待服务恢复... (尝试 ",p,"/60)"]})]}),h==="success"&&e.jsxs(e.Fragment,{children:[e.jsx(fa,{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:"正在跳转到登录页面..."})]}),h==="failed"&&e.jsxs(e.Fragment,{children:[e.jsx(Sa,{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:"服务未能在预期时间内恢复,请手动检查或刷新页面"})]})]}),h!=="failed"&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(wr,{value:c,className:"h-2"}),e.jsxs("div",{className:"flex justify-between text-sm text-muted-foreground",children:[e.jsxs("span",{children:[c,"%"]}),e.jsxs("span",{children:["已用时: ",y(x)]})]})]}),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:[h==="restarting"&&"🔄 配置已保存,正在重启主程序...",h==="checking"&&"⏳ 正在等待服务恢复,请勿关闭页面...",h==="success"&&"✅ 配置已生效,服务运行正常",h==="failed"&&"⚠️ 如果长时间无响应,请尝试手动重启"]})}),h==="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:()=>{f("checking"),w(0),v()},className:"flex-1 px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/90",children:"重试检测"})]})]})})}const L0={name:"toml",startState:function(){return{inString:!1,stringType:"",lhs:!0,inArray:0}},token:function(n,i){let c;if(!i.inString&&(c=n.match(/^('''|"""|'|")/))&&(i.stringType=c[0],i.inString=!0),n.sol()&&!i.inString&&i.inArray===0&&(i.lhs=!0),i.inString){for(;i.inString;)if(n.match(i.stringType))i.inString=!1;else if(n.peek()==="\\")n.next(),n.next();else{if(n.eol())break;n.match(/^.[^\\\"\']*/)}return i.lhs?"property":"string"}else{if(i.inArray&&n.peek()==="]")return n.next(),i.inArray--,"bracket";if(i.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(i.lhs&&n.eatWhile(function(d){return d!="="&&d!=" "}))return"property";if(i.lhs&&n.peek()==="=")return n.next(),i.lhs=!1,null;if(!i.lhs&&n.match(/^\d\d\d\d[\d\-\:\.T]*Z/))return"atom";if(!i.lhs&&(n.match("true")||n.match("false")))return"atom";if(!i.lhs&&n.peek()==="[")return i.inArray++,n.next(),"bracket";if(!i.lhs&&n.match(/^\-?\d+(?:\.\d+)?/))return"number";n.eatSpace()||n.next()}return null},languageData:{commentTokens:{line:"#"}}},U0={python:[Qb()],json:[Yb(),Xb()],toml:[$b.define(L0)],text:[]};function B0({value:n,onChange:i,language:c="text",readOnly:d=!1,height:h="400px",minHeight:f,maxHeight:x,placeholder:j,theme:p="dark",className:w=""}){const[v,y]=u.useState(!1);if(u.useEffect(()=>{y(!0)},[]),!v)return e.jsx("div",{className:`rounded-md border bg-muted animate-pulse ${w}`,style:{height:h,minHeight:f,maxHeight:x}});const S=[...U0[c]||[],If.lineWrapping];return d&&S.push(If.editable.of(!1)),e.jsx("div",{className:`rounded-md overflow-hidden border ${w}`,children:e.jsx(Kb,{value:n,height:h,minHeight:f,maxHeight:x,theme:p==="dark"?Jb:void 0,extensions:S,onChange:i,placeholder:j,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 H0(){const[n,i]=u.useState(!0),[c,d]=u.useState(!1),[h,f]=u.useState(!1),[x,j]=u.useState(!1),[p,w]=u.useState(!1),[v,y]=u.useState(!1),[S,k]=u.useState("visual"),[O,Y]=u.useState(""),[L,R]=u.useState(!1),{toast:H}=Vs(),[D,C]=u.useState(null),[$,G]=u.useState(null),[T,M]=u.useState(null),[ne,fe]=u.useState(null),[_e,Se]=u.useState(null),[je,ye]=u.useState(null),[be,A]=u.useState(null),[K,E]=u.useState(null),[se,_]=u.useState(null),[me,re]=u.useState(null),[le,pe]=u.useState(null),[Ne,he]=u.useState(null),[Q,P]=u.useState(null),[q,W]=u.useState(null),[Ce,Me]=u.useState(null),[ce,De]=u.useState(null),[Fs,Qs]=u.useState(null),[ue,Ee]=u.useState(null),as=u.useRef(null),Ke=u.useRef(!0),lt=u.useRef({}),Ot=u.useCallback(async()=>{try{const ke=await E0();Y(ke),R(!1)}catch(ke){H({variant:"destructive",title:"加载失败",description:ke instanceof Error?ke.message:"加载源代码失败"})}},[H]),bt=u.useCallback(async()=>{try{i(!0);const ke=await cp();lt.current=ke,C(ke.bot),G(ke.personality);const ve=ke.chat;ve.talk_value_rules||(ve.talk_value_rules=[]),M(ve),fe(ke.expression),Se(ke.emoji),ye(ke.memory),A(ke.tool),E(ke.mood),_(ke.voice),re(ke.lpmm_knowledge),pe(ke.keyword_reaction),he(ke.response_post_process),P(ke.chinese_typo),W(ke.response_splitter),Me(ke.log),De(ke.debug),Qs(ke.maim_message),Ee(ke.telemetry),j(!1),Ke.current=!1,await Ot()}catch(ke){console.error("加载配置失败:",ke),H({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}finally{i(!1)}},[H,Ot]);u.useEffect(()=>{bt()},[bt]);const Pe=u.useCallback(async(ke,ve)=>{if(!Ke.current)try{f(!0),await A0(ke,ve),j(!1)}catch(is){console.error(`自动保存 ${ke} 失败:`,is),j(!0)}finally{f(!1)}},[]),U=u.useCallback((ke,ve)=>{Ke.current||(j(!0),as.current&&clearTimeout(as.current),as.current=setTimeout(()=>{Pe(ke,ve)},2e3))},[Pe]);u.useEffect(()=>{D&&!Ke.current&&U("bot",D)},[D,U]),u.useEffect(()=>{$&&!Ke.current&&U("personality",$)},[$,U]),u.useEffect(()=>{T&&!Ke.current&&U("chat",T)},[T,U]),u.useEffect(()=>{ne&&!Ke.current&&U("expression",ne)},[ne,U]),u.useEffect(()=>{_e&&!Ke.current&&U("emoji",_e)},[_e,U]),u.useEffect(()=>{je&&!Ke.current&&U("memory",je)},[je,U]),u.useEffect(()=>{be&&!Ke.current&&U("tool",be)},[be,U]),u.useEffect(()=>{K&&!Ke.current&&U("mood",K)},[K,U]),u.useEffect(()=>{se&&!Ke.current&&U("voice",se)},[se,U]),u.useEffect(()=>{me&&!Ke.current&&U("lpmm_knowledge",me)},[me,U]),u.useEffect(()=>{le&&!Ke.current&&U("keyword_reaction",le)},[le,U]),u.useEffect(()=>{Ne&&!Ke.current&&U("response_post_process",Ne)},[Ne,U]),u.useEffect(()=>{Q&&!Ke.current&&U("chinese_typo",Q)},[Q,U]),u.useEffect(()=>{q&&!Ke.current&&U("response_splitter",q)},[q,U]),u.useEffect(()=>{Ce&&!Ke.current&&U("log",Ce)},[Ce,U]),u.useEffect(()=>{ce&&!Ke.current&&U("debug",ce)},[ce,U]),u.useEffect(()=>{Fs&&!Ke.current&&U("maim_message",Fs)},[Fs,U]),u.useEffect(()=>{ue&&!Ke.current&&U("telemetry",ue)},[ue,U]);const Re=async()=>{try{d(!0),await z0(O),j(!1),R(!1),H({title:"保存成功",description:"配置已保存"}),await bt()}catch(ke){R(!0),H({variant:"destructive",title:"保存失败",description:ke instanceof Error?ke.message:"保存配置失败"})}finally{d(!1)}},ze=async ke=>{if(x){H({variant:"destructive",title:"切换失败",description:"请先保存当前更改"});return}if(k(ke),ke==="source")await Ot();else try{const ve=await cp();lt.current=ve,C(ve.bot),G(ve.personality);const is=ve.chat;is.talk_value_rules||(is.talk_value_rules=[]),M(is),fe(ve.expression),Se(ve.emoji),ye(ve.memory),A(ve.tool),E(ve.mood),_(ve.voice),re(ve.lpmm_knowledge),pe(ve.keyword_reaction),he(ve.response_post_process),P(ve.chinese_typo),W(ve.response_splitter),Me(ve.log),De(ve.debug),Qs(ve.maim_message),Ee(ve.telemetry),j(!1)}catch(ve){console.error("加载配置失败:",ve),H({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}},Ye=async()=>{try{d(!0),as.current&&clearTimeout(as.current);const ke={...lt.current,bot:D,personality:$,chat:T,expression:ne,emoji:_e,memory:je,tool:be,mood:K,voice:se,lpmm_knowledge:me,keyword_reaction:le,response_post_process:Ne,chinese_typo:Q,response_splitter:q,log:Ce,debug:ce,maim_message:Fs,telemetry:ue};await op(ke),j(!1),H({title:"保存成功",description:"麦麦主程序配置已保存"})}catch(ke){console.error("保存配置失败:",ke),H({title:"保存失败",description:ke.message,variant:"destructive"})}finally{d(!1)}},zs=async()=>{try{w(!0),lo().catch(()=>{}),y(!0)}catch(ke){console.error("重启失败:",ke),y(!1),H({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),w(!1)}},We=async()=>{try{d(!0),as.current&&clearTimeout(as.current);const ke={...lt.current,bot:D,personality:$,chat:T,expression:ne,emoji:_e,memory:je,tool:be,mood:K,voice:se,lpmm_knowledge:me,keyword_reaction:le,response_post_process:Ne,chinese_typo:Q,response_splitter:q,log:Ce,debug:ce,maim_message:Fs,telemetry:ue};await op(ke),j(!1),H({title:"保存成功",description:"配置已保存,即将重启麦麦..."}),await new Promise(ve=>setTimeout(ve,500)),await zs()}catch(ke){console.error("保存失败:",ke),H({title:"保存失败",description:ke.message,variant:"destructive"})}finally{d(!1)}},nt=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},vs=()=>{y(!1),w(!1),H({title:"重启失败",description:"服务器未能在预期时间内恢复,请手动检查",variant:"destructive"})};return n?e.jsx(ss,{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(ss,{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(N,{onClick:S==="visual"?Ye:Re,disabled:c||h||!x||p,size:"sm",variant:"outline",className:"w-20 sm:w-24",children:[e.jsx(yr,{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:c?"保存中":h?"自动":x?"保存":"已保存"})]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{disabled:c||h||p,size:"sm",className:"w-20 sm:w-28",children:[e.jsx(br,{className:"h-4 w-4 flex-shrink-0"}),e.jsx("span",{className:"ml-1 truncate text-xs sm:text-sm",children:p?"重启中":x?"保存重启":"重启"})]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认重启麦麦?"}),e.jsx(us,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:x?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:x?We:zs,children:x?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsx("div",{className:"flex",children:e.jsx(Ca,{value:S,onValueChange:ke=>ze(ke),className:"w-full",children:e.jsxs(pa,{className:"h-8 sm:h-9 w-full grid grid-cols-2",children:[e.jsxs(ns,{value:"visual",className:"text-xs sm:text-sm",children:[e.jsx(wb,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"可视化编辑"]}),e.jsxs(ns,{value:"source",className:"text-xs sm:text-sm",children:[e.jsx(_b,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"源代码编辑"]})]})})})]}),e.jsxs(cl,{children:[e.jsx(La,{className:"h-4 w-4"}),e.jsxs(ol,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),S==="source"&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs(cl,{children:[e.jsx(La,{className:"h-4 w-4"}),e.jsxs(ol,{children:[e.jsx("strong",{children:"源代码模式(高级功能):"}),"直接编辑 TOML 配置文件。此功能仅适用于熟悉 TOML 语法的高级用户。保存时会在后端验证格式,只有格式完全正确才能保存。",L&&e.jsx("span",{className:"text-destructive font-semibold ml-2",children:"⚠️ 上次保存失败,请检查 TOML 格式"})]})]}),e.jsx(B0,{value:O,onChange:ke=>{Y(ke),j(!0),L&&R(!1)},language:"toml",theme:"dark",height:"calc(100vh - 280px)",minHeight:"500px",placeholder:"TOML 配置内容"})]}),S==="visual"&&e.jsx(e.Fragment,{children:e.jsxs(Ca,{defaultValue:"bot",className:"w-full",children:[e.jsxs(pa,{className:"flex flex-wrap h-auto gap-1 p-1 sm:grid sm:grid-cols-5 lg:grid-cols-10",children:[e.jsx(ns,{value:"bot",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"基本信息"}),e.jsx(ns,{value:"personality",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"人格"}),e.jsx(ns,{value:"chat",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"聊天"}),e.jsx(ns,{value:"expression",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"表达"}),e.jsx(ns,{value:"features",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"功能"}),e.jsx(ns,{value:"processing",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"处理"}),e.jsx(ns,{value:"mood",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"情绪"}),e.jsx(ns,{value:"voice",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"语音"}),e.jsx(ns,{value:"lpmm",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"知识库"}),e.jsx(ns,{value:"other",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"其他"})]}),e.jsx(Es,{value:"bot",className:"space-y-4",children:D&&e.jsx(q0,{config:D,onChange:C})}),e.jsx(Es,{value:"personality",className:"space-y-4",children:$&&e.jsx(G0,{config:$,onChange:G})}),e.jsx(Es,{value:"chat",className:"space-y-4",children:T&&e.jsx(V0,{config:T,onChange:M})}),e.jsx(Es,{value:"expression",className:"space-y-4",children:ne&&e.jsx($0,{config:ne,onChange:fe})}),e.jsx(Es,{value:"features",className:"space-y-4",children:_e&&je&&be&&e.jsx(Q0,{emojiConfig:_e,memoryConfig:je,toolConfig:be,onEmojiChange:Se,onMemoryChange:ye,onToolChange:A})}),e.jsx(Es,{value:"processing",className:"space-y-4",children:le&&Ne&&Q&&q&&e.jsx(Y0,{keywordReactionConfig:le,responsePostProcessConfig:Ne,chineseTypoConfig:Q,responseSplitterConfig:q,onKeywordReactionChange:pe,onResponsePostProcessChange:he,onChineseTypoChange:P,onResponseSplitterChange:W})}),e.jsx(Es,{value:"mood",className:"space-y-4",children:K&&e.jsx(X0,{config:K,onChange:E})}),e.jsx(Es,{value:"voice",className:"space-y-4",children:se&&e.jsx(K0,{config:se,onChange:_})}),e.jsx(Es,{value:"lpmm",className:"space-y-4",children:me&&e.jsx(J0,{config:me,onChange:re})}),e.jsxs(Es,{value:"other",className:"space-y-4",children:[Ce&&e.jsx(Z0,{config:Ce,onChange:Me}),ce&&e.jsx(I0,{config:ce,onChange:De}),Fs&&e.jsx(P0,{config:Fs,onChange:Qs}),ue&&e.jsx(W0,{config:ue,onChange:Ee})]})]})}),v&&e.jsx(Pu,{onRestartComplete:nt,onRestartFailed:vs})]})})}function q0({config:n,onChange:i}){const c=()=>{i({...n,platforms:[...n.platforms,""]})},d=p=>{i({...n,platforms:n.platforms.filter((w,v)=>v!==p)})},h=(p,w)=>{const v=[...n.platforms];v[p]=w,i({...n,platforms:v})},f=()=>{i({...n,alias_names:[...n.alias_names,""]})},x=p=>{i({...n,alias_names:n.alias_names.filter((w,v)=>v!==p)})},j=(p,w)=>{const v=[...n.alias_names];v[p]=w,i({...n,alias_names:v})};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(b,{htmlFor:"platform",children:"平台"}),e.jsx(ie,{id:"platform",value:n.platform,onChange:p=>i({...n,platform:p.target.value}),placeholder:"qq"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"qq_account",children:"QQ账号"}),e.jsx(ie,{id:"qq_account",value:n.qq_account,onChange:p=>i({...n,qq_account:p.target.value}),placeholder:"123456789"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"nickname",children:"昵称"}),e.jsx(ie,{id:"nickname",value:n.nickname,onChange:p=>i({...n,nickname:p.target.value}),placeholder:"麦麦"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{children:"其他平台账号"}),e.jsxs(N,{onClick:c,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[n.platforms.map((p,w)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:p,onChange:v=>h(w,v.target.value),placeholder:"wx:114514"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除平台账号 "',p||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d(w),children:"删除"})]})]})]})]},w)),n.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(b,{children:"别名"}),e.jsxs(N,{onClick:f,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[n.alias_names.map((p,w)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:p,onChange:v=>j(w,v.target.value),placeholder:"小麦"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除别名 "',p||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>x(w),children:"删除"})]})]})]})]},w)),n.alias_names.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无别名"})]})]})]})]})})}function G0({config:n,onChange:i}){const c=()=>{i({...n,states:[...n.states,""]})},d=f=>{i({...n,states:n.states.filter((x,j)=>j!==f)})},h=(f,x)=>{const j=[...n.states];j[f]=x,i({...n,states:j})};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(b,{htmlFor:"personality",children:"人格特质"}),e.jsx(Bs,{id:"personality",value:n.personality,onChange:f=>i({...n,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(b,{htmlFor:"reply_style",children:"表达风格"}),e.jsx(Bs,{id:"reply_style",value:n.reply_style,onChange:f=>i({...n,reply_style:f.target.value}),placeholder:"描述说话的表达风格和习惯",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"interest",children:"兴趣"}),e.jsx(Bs,{id:"interest",value:n.interest,onChange:f=>i({...n,interest:f.target.value}),placeholder:"会影响麦麦对什么话题进行回复",rows:2})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"plan_style",children:"说话规则与行为风格"}),e.jsx(Bs,{id:"plan_style",value:n.plan_style,onChange:f=>i({...n,plan_style:f.target.value}),placeholder:"麦麦的说话规则和行为风格",rows:5})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"visual_style",children:"识图规则"}),e.jsx(Bs,{id:"visual_style",value:n.visual_style,onChange:f=>i({...n,visual_style:f.target.value}),placeholder:"识图时的处理规则",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"private_plan_style",children:"私聊规则"}),e.jsx(Bs,{id:"private_plan_style",value:n.private_plan_style,onChange:f=>i({...n,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(b,{children:"状态列表(人格多样性)"}),e.jsxs(N,{onClick:c,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加状态"]})]}),e.jsx("div",{className:"space-y-2",children:n.states.map((f,x)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Bs,{value:f,onChange:j=>h(x,j.target.value),placeholder:"描述一个人格状态",rows:2}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsx(us,{children:"确定要删除这个人格状态吗?此操作无法撤销。"})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d(x),children:"删除"})]})]})]})]},x))})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"state_probability",children:"状态替换概率"}),e.jsx(ie,{id:"state_probability",type:"number",step:"0.1",min:"0",max:"1",value:n.state_probability,onChange:f=>i({...n,state_probability:parseFloat(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"每次构建人格时替换 personality 的概率(0.0-1.0)"})]})]})]})})}function V0({config:n,onChange:i}){const c=()=>{i({...n,talk_value_rules:[...n.talk_value_rules,{target:"",time:"00:00-23:59",value:1}]})},d=j=>{i({...n,talk_value_rules:n.talk_value_rules.filter((p,w)=>w!==j)})},h=(j,p,w)=>{const v=[...n.talk_value_rules];v[j]={...v[j],[p]:w},i({...n,talk_value_rules:v})},f=({value:j,onChange:p})=>{const[w,v]=u.useState("00"),[y,S]=u.useState("00"),[k,O]=u.useState("23"),[Y,L]=u.useState("59");u.useEffect(()=>{const H=j.split("-");if(H.length===2){const[D,C]=H,[$,G]=D.split(":"),[T,M]=C.split(":");$&&v($.padStart(2,"0")),G&&S(G.padStart(2,"0")),T&&O(T.padStart(2,"0")),M&&L(M.padStart(2,"0"))}},[j]);const R=(H,D,C,$)=>{const G=`${H}:${D}-${C}:${$}`;p(G)};return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",className:"w-full justify-start font-mono text-sm",children:[e.jsx(li,{className:"h-4 w-4 mr-2"}),j||"选择时间段"]})}),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(b,{className:"text-xs",children:"小时"}),e.jsxs(Be,{value:w,onValueChange:H=>{v(H),R(H,y,k,Y)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:Array.from({length:24},(H,D)=>D).map(H=>e.jsx(te,{value:H.toString().padStart(2,"0"),children:H.toString().padStart(2,"0")},H))})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs",children:"分钟"}),e.jsxs(Be,{value:y,onValueChange:H=>{S(H),R(w,H,k,Y)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:Array.from({length:60},(H,D)=>D).map(H=>e.jsx(te,{value:H.toString().padStart(2,"0"),children:H.toString().padStart(2,"0")},H))})]})]})]})]}),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(b,{className:"text-xs",children:"小时"}),e.jsxs(Be,{value:k,onValueChange:H=>{O(H),R(w,y,H,Y)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:Array.from({length:24},(H,D)=>D).map(H=>e.jsx(te,{value:H.toString().padStart(2,"0"),children:H.toString().padStart(2,"0")},H))})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs",children:"分钟"}),e.jsxs(Be,{value:Y,onValueChange:H=>{L(H),R(w,y,k,H)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:Array.from({length:60},(H,D)=>D).map(H=>e.jsx(te,{value:H.toString().padStart(2,"0"),children:H.toString().padStart(2,"0")},H))})]})]})]})]})]})})]})},x=({rule:j})=>{const p=`{ target = "${j.target}", time = "${j.time}", value = ${j.value.toFixed(1)} }`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{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:p}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})};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(b,{htmlFor:"talk_value",children:"聊天频率(基础值)"}),e.jsx(ie,{id:"talk_value",type:"number",step:"0.1",min:"0",max:"1",value:n.talk_value,onChange:j=>i({...n,talk_value:parseFloat(j.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(Qe,{id:"mentioned_bot_reply",checked:n.mentioned_bot_reply,onCheckedChange:j=>i({...n,mentioned_bot_reply:j})}),e.jsx(b,{htmlFor:"mentioned_bot_reply",className:"cursor-pointer",children:"启用提及必回复"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"max_context_size",children:"上下文长度"}),e.jsx(ie,{id:"max_context_size",type:"number",min:"1",value:n.max_context_size,onChange:j=>i({...n,max_context_size:parseInt(j.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"planner_smooth",children:"规划器平滑"}),e.jsx(ie,{id:"planner_smooth",type:"number",step:"1",min:"0",value:n.planner_smooth,onChange:j=>i({...n,planner_smooth:parseFloat(j.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(Qe,{id:"enable_talk_value_rules",checked:n.enable_talk_value_rules,onCheckedChange:j=>i({...n,enable_talk_value_rules:j})}),e.jsx(b,{htmlFor:"enable_talk_value_rules",className:"cursor-pointer",children:"启用动态发言频率规则"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{id:"include_planner_reasoning",checked:n.include_planner_reasoning,onCheckedChange:j=>i({...n,include_planner_reasoning:j})}),e.jsx(b,{htmlFor:"include_planner_reasoning",className:"cursor-pointer",children:"将 planner 推理加入 replyer"})]})]})]}),n.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(N,{onClick:c,size:"sm",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),n.talk_value_rules&&n.talk_value_rules.length>0?e.jsx("div",{className:"space-y-4",children:n.talk_value_rules.map((j,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(x,{rule:j}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{variant:"ghost",size:"sm",children:e.jsx(ts,{className:"h-4 w-4 text-destructive"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除规则 #",p+1," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d(p),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(Be,{value:j.target===""?"global":"specific",onValueChange:w=>{w==="global"?h(p,"target",""):h(p,"target","qq::group")},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"global",children:"全局配置"}),e.jsx(te,{value:"specific",children:"详细配置"})]})]})]}),j.target!==""&&(()=>{const w=j.target.split(":"),v=w[0]||"qq",y=w[1]||"",S=w[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(b,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Be,{value:v,onValueChange:k=>{h(p,"target",`${k}:${y}:${S}`)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"qq",children:"QQ"}),e.jsx(te,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(ie,{value:y,onChange:k=>{h(p,"target",`${v}:${k.target.value}:${S}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Be,{value:S,onValueChange:k=>{h(p,"target",`${v}:${y}:${k}`)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"group",children:"群组(group)"}),e.jsx(te,{value:"private",children:"私聊(private)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前聊天流 ID:",j.target||"(未设置)"]})]})})(),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"时间段 (Time)"}),e.jsx(f,{value:j.time,onChange:w=>h(p,"time",w)}),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(b,{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:j.value,onChange:w=>{const v=parseFloat(w.target.value);isNaN(v)||h(p,"value",Math.max(.01,Math.min(1,v)))},className:"w-20 h-8 text-xs"})]}),e.jsx(wa,{value:[j.value],onValueChange:w=>h(p,"value",w[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 表示正常发言"]})]})]})]})]})}function F0({member:n,groupIndex:i,memberIndex:c,availableChatIds:d,onUpdate:h,onRemove:f}){const x=d.includes(n)||n==="*",[j,p]=u.useState(!x);return e.jsxs("div",{className:"flex gap-2",children:[e.jsx("div",{className:"flex-1 flex gap-2",children:j?e.jsxs(e.Fragment,{children:[e.jsx(ie,{value:n,onChange:w=>h(i,c,w.target.value),placeholder:'输入 "*" 或 "qq:123456:group"',className:"flex-1"}),d.length>0&&e.jsx(N,{size:"sm",variant:"outline",onClick:()=>p(!1),title:"切换到下拉选择",children:"下拉"})]}):e.jsxs(e.Fragment,{children:[e.jsxs(Be,{value:n,onValueChange:w=>h(i,c,w),children:[e.jsx(Le,{className:"flex-1",children:e.jsx(He,{placeholder:"选择聊天流"})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"*",children:"* (全局共享)"}),d.map((w,v)=>e.jsx(te,{value:w,children:w},v))]})]}),e.jsx(N,{size:"sm",variant:"outline",onClick:()=>p(!0),title:"切换到手动输入",children:"输入"})]})}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除组成员 "',n||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>f(i,c),children:"删除"})]})]})]})]})}function $0({config:n,onChange:i}){const c=()=>{i({...n,learning_list:[...n.learning_list,["","enable","enable","1.0"]]})},d=y=>{i({...n,learning_list:n.learning_list.filter((S,k)=>k!==y)})},h=(y,S,k)=>{const O=[...n.learning_list];O[y][S]=k,i({...n,learning_list:O})},f=({rule:y})=>{const S=`["${y[0]}", "${y[1]}", "${y[2]}", "${y[3]}"]`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{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:S}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},x=()=>{i({...n,expression_groups:[...n.expression_groups,[]]})},j=y=>{i({...n,expression_groups:n.expression_groups.filter((S,k)=>k!==y)})},p=y=>{const S=[...n.expression_groups];S[y]=[...S[y],""],i({...n,expression_groups:S})},w=(y,S)=>{const k=[...n.expression_groups];k[y]=k[y].filter((O,Y)=>Y!==S),i({...n,expression_groups:k})},v=(y,S,k)=>{const O=[...n.expression_groups];O[y][S]=k,i({...n,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(N,{onClick:c,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),e.jsxs("div",{className:"space-y-4",children:[n.learning_list.map((y,S)=>{const k=n.learning_list.some((D,C)=>C!==S&&D[0]===""),O=y[0]==="",Y=y[0].split(":"),L=Y[0]||"qq",R=Y[1]||"",H=Y[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(f,{rule:y}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除学习规则 ",S+1," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d(S),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(Be,{value:O?"global":"specific",onValueChange:D=>{D==="global"?h(S,0,""):h(S,0,"qq::group")},disabled:k&&!O,children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"global",children:"全局配置"}),e.jsx(te,{value:"specific",disabled:k&&!O,children:"详细配置"})]})]}),k&&!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(b,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Be,{value:L,onValueChange:D=>{h(S,0,`${D}:${R}:${H}`)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"qq",children:"QQ"}),e.jsx(te,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(ie,{value:R,onChange:D=>{h(S,0,`${L}:${D.target.value}:${H}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Be,{value:H,onValueChange:D=>{h(S,0,`${L}:${R}:${D}`)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"group",children:"群组(group)"}),e.jsx(te,{value:"private",children:"私聊(private)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前聊天流 ID:",y[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(b,{className:"text-xs font-medium",children:"使用学到的表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦使用从聊天中学到的表达方式"})]}),e.jsx(Qe,{checked:y[1]==="enable",onCheckedChange:D=>h(S,1,D?"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(b,{className:"text-xs font-medium",children:"学习表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦从聊天中学习新的表达方式"})]}),e.jsx(Qe,{checked:y[2]==="enable",onCheckedChange:D=>h(S,2,D?"enable":"disable")})]})}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{className:"text-xs font-medium",children:"学习强度"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"5",value:y[3],onChange:D=>{const C=parseFloat(D.target.value);isNaN(C)||h(S,3,Math.max(0,Math.min(5,C)).toFixed(1))},className:"w-20 h-8 text-xs"})]}),e.jsx(wa,{value:[parseFloat(y[3])||1],onValueChange:D=>h(S,3,D[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)}),n.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(Qe,{checked:n.reflect,onCheckedChange:y=>i({...n,reflect:y})})]}),n.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=(n.reflect_operator_id||"").split(":"),k=S[0]||"qq",O=S[1]||"",Y=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(b,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Be,{value:k,onValueChange:L=>{i({...n,reflect_operator_id:`${L}:${O}:${Y}`})},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"qq",children:"QQ"}),e.jsx(te,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"用户/群 ID"}),e.jsx(ie,{value:O,onChange:L=>{i({...n,reflect_operator_id:`${k}:${L.target.value}:${Y}`})},placeholder:"输入 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Be,{value:Y,onValueChange:L=>{i({...n,reflect_operator_id:`${k}:${O}:${L}`})},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"private",children:"私聊(private)"}),e.jsx(te,{value:"group",children:"群组(group)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前操作员 ID:",n.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(N,{onClick:()=>{i({...n,allow_reflect:[...n.allow_reflect||[],"qq::group"]})},size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加聊天流"]})]}),e.jsxs("div",{className:"space-y-2",children:[(n.allow_reflect||[]).map((y,S)=>{const k=y.split(":"),O=k[0]||"qq",Y=k[1]||"",L=k[2]||"group";return e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-muted/50",children:[e.jsxs(Be,{value:O,onValueChange:R=>{const H=[...n.allow_reflect];H[S]=`${R}:${Y}:${L}`,i({...n,allow_reflect:H})},children:[e.jsx(Le,{className:"w-24",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"qq",children:"QQ"}),e.jsx(te,{value:"wx",children:"微信"})]})]}),e.jsx(ie,{value:Y,onChange:R=>{const H=[...n.allow_reflect];H[S]=`${O}:${R.target.value}:${L}`,i({...n,allow_reflect:H})},placeholder:"ID",className:"flex-1 font-mono text-sm"}),e.jsxs(Be,{value:L,onValueChange:R=>{const H=[...n.allow_reflect];H[S]=`${O}:${Y}:${R}`,i({...n,allow_reflect:H})},children:[e.jsx(Le,{className:"w-32",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"group",children:"群组"}),e.jsx(te,{value:"private",children:"私聊"})]})]}),e.jsx(N,{onClick:()=>{i({...n,allow_reflect:n.allow_reflect.filter((R,H)=>H!==S)})},size:"sm",variant:"ghost",children:e.jsx(ts,{className:"h-4 w-4"})})]},S)}),(!n.allow_reflect||n.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(N,{onClick:x,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加共享组"]})]}),e.jsxs("div",{className:"space-y-4",children:[n.expression_groups.map((y,S)=>{const k=n.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,y.length===1&&y[0]==="*"&&"(全局共享)"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(N,{onClick:()=>p(S),size:"sm",variant:"outline",children:e.jsx(ot,{className:"h-4 w-4"})}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除共享组 ",S+1," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>j(S),children:"删除"})]})]})]})]})]}),e.jsx("div",{className:"space-y-2",children:y.map((O,Y)=>e.jsx(F0,{member:O,groupIndex:S,memberIndex:Y,availableChatIds:k,onUpdate:v,onRemove:w},`${S}-${Y}`))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:'提示:可以从下拉框选择已配置的聊天流,或手动输入。输入 "*" 启用全局共享'})]},S)}),n.expression_groups.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无共享组,点击"添加共享组"开始配置'})]})]})})]})}function Q0({emojiConfig:n,memoryConfig:i,toolConfig:c,onEmojiChange:d,onMemoryChange:h,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(Qe,{id:"enable_tool",checked:c.enable_tool,onCheckedChange:x=>f({...c,enable_tool:x})}),e.jsx(b,{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-2",children:[e.jsx(b,{htmlFor:"max_agent_iterations",children:"记忆思考深度"}),e.jsx(ie,{id:"max_agent_iterations",type:"number",min:"1",value:i.max_agent_iterations,onChange:x=>h({...i,max_agent_iterations:parseInt(x.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"最低为 1(不深入思考)"})]})]})}),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(b,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsx(ie,{id:"emoji_chance",type:"number",step:"0.1",min:"0",max:"1",value:n.emoji_chance,onChange:x=>d({...n,emoji_chance:parseFloat(x.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"范围 0-1,越大越容易发送表情包"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"max_reg_num",children:"最大注册数量"}),e.jsx(ie,{id:"max_reg_num",type:"number",min:"1",value:n.max_reg_num,onChange:x=>d({...n,max_reg_num:parseInt(x.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦最多可以注册的表情包数量"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(ie,{id:"check_interval",type:"number",min:"1",value:n.check_interval,onChange:x=>d({...n,check_interval:parseInt(x.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(Qe,{id:"do_replace",checked:n.do_replace,onCheckedChange:x=>d({...n,do_replace:x})}),e.jsx(b,{htmlFor:"do_replace",className:"cursor-pointer",children:"达到最大数量时替换表情包"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{id:"steal_emoji",checked:n.steal_emoji,onCheckedChange:x=>d({...n,steal_emoji:x})}),e.jsx(b,{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(Qe,{id:"content_filtration",checked:n.content_filtration,onCheckedChange:x=>d({...n,content_filtration:x})}),e.jsx(b,{htmlFor:"content_filtration",className:"cursor-pointer",children:"启用表情包过滤"})]}),n.content_filtration&&e.jsxs("div",{className:"grid gap-2 pl-6 border-l-2 border-primary/20",children:[e.jsx(b,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(ie,{id:"filtration_prompt",value:n.filtration_prompt,onChange:x=>d({...n,filtration_prompt:x.target.value}),placeholder:"符合公序良俗"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只有符合此要求的表情包才会被保存"})]})]})]})})]})}function Y0({keywordReactionConfig:n,responsePostProcessConfig:i,chineseTypoConfig:c,responseSplitterConfig:d,onKeywordReactionChange:h,onResponsePostProcessChange:f,onChineseTypoChange:x,onResponseSplitterChange:j}){const p=()=>{h({...n,regex_rules:[...n.regex_rules,{regex:[""],reaction:""}]})},w=C=>{h({...n,regex_rules:n.regex_rules.filter(($,G)=>G!==C)})},v=(C,$,G)=>{const T=[...n.regex_rules];$==="regex"&&typeof G=="string"?T[C]={...T[C],regex:[G]}:$==="reaction"&&typeof G=="string"&&(T[C]={...T[C],reaction:G}),h({...n,regex_rules:T})},y=({regex:C,reaction:$,onRegexChange:G,onReactionChange:T})=>{const[M,ne]=u.useState(!1),[fe,_e]=u.useState(""),[Se,je]=u.useState(null),[ye,be]=u.useState(""),[A,K]=u.useState({}),[E,se]=u.useState(""),_=u.useRef(null),[me,re]=u.useState("build"),le=Q=>Q.replace(/\(\?P<([^>]+)>/g,"(?<$1>"),pe=(Q,P=0)=>{const q=_.current;if(!q)return;const W=q.selectionStart||0,Ce=q.selectionEnd||0,Me=C.substring(0,W)+Q+C.substring(Ce);G(Me),setTimeout(()=>{const ce=W+Q.length+P;q.setSelectionRange(ce,ce),q.focus()},0)};u.useEffect(()=>{if(!C||!fe){je(null),K({}),se($),be("");return}try{const Q=le(C),P=new RegExp(Q,"g"),q=fe.match(P);je(q),be("");const Ce=new RegExp(Q).exec(fe);if(Ce&&Ce.groups){K(Ce.groups);let Me=$;Object.entries(Ce.groups).forEach(([ce,De])=>{Me=Me.replace(new RegExp(`\\[${ce}\\]`,"g"),De||"")}),se(Me)}else K({}),se($)}catch(Q){be(Q.message),je(null),K({}),se($)}},[C,fe,$]);const Ne=()=>{if(!fe||!Se||Se.length===0)return e.jsx("span",{className:"text-muted-foreground",children:fe||"请输入测试文本"});try{const Q=le(C),P=new RegExp(Q,"g");let q=0;const W=[];let Ce;for(;(Ce=P.exec(fe))!==null;)Ce.index>q&&W.push(e.jsx("span",{children:fe.substring(q,Ce.index)},`text-${q}`)),W.push(e.jsx("span",{className:"bg-yellow-200 dark:bg-yellow-900 font-semibold",children:Ce[0]},`match-${Ce.index}`)),q=Ce.index+Ce[0].length;return q)",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($s,{open:M,onOpenChange:ne,children:[e.jsx(Zu,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Qu,{className:"h-4 w-4 mr-1"}),"正则编辑器"]})}),e.jsxs(Hs,{className:"max-w-[95vw] sm:max-w-[900px] max-h-[90vh]",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"正则表达式编辑器"}),e.jsx(Is,{className:"text-sm",children:"使用可视化工具构建正则表达式,并实时测试效果"})]}),e.jsx(ss,{className:"max-h-[calc(90vh-120px)]",children:e.jsxs(Ca,{value:me,onValueChange:Q=>re(Q),className:"w-full",children:[e.jsxs(pa,{className:"grid w-full grid-cols-2",children:[e.jsx(ns,{value:"build",children:"🔧 构建器"}),e.jsx(ns,{value:"test",children:"🧪 测试器"})]}),e.jsxs(Es,{value:"build",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"正则表达式"}),e.jsx(ie,{ref:_,value:C,onChange:Q=>G(Q.target.value),className:"font-mono text-sm",placeholder:"点击下方按钮构建正则表达式..."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"Reaction 内容"}),e.jsx(Bs,{value:$,onChange:Q=>T(Q.target.value),placeholder:"使用 [捕获组名] 引用捕获的内容...",rows:3,className:"text-sm"})]}),e.jsxs("div",{className:"space-y-4 border-t pt-4",children:[he.map(Q=>e.jsxs("div",{className:"space-y-2",children:[e.jsx("h5",{className:"text-xs font-semibold text-primary",children:Q.category}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:Q.items.map(P=>e.jsx(N,{variant:"outline",size:"sm",className:"justify-start h-auto py-2 px-3",onClick:()=>pe(P.pattern,P.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:P.label}),e.jsx("code",{className:"ml-auto text-xs bg-muted px-1.5 py-0.5 rounded font-mono",children:P.pattern})]}),e.jsx("span",{className:"text-xs text-muted-foreground mt-0.5",children:P.desc})]})},P.label))})]},Q.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(N,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>G("^(?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(N,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>G("(?:[^,。.\\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(N,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>G("(?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(Es,{value:"test",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"当前正则表达式"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:C||"(未设置)"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"test-text",className:"text-sm font-medium",children:"测试文本"}),e.jsx(Bs,{id:"test-text",value:fe,onChange:Q=>_e(Q.target.value),placeholder:`在此输入要测试的文本... +例如:打游戏是这样的`,className:"min-h-[100px] text-sm"})]}),ye&&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:ye})]}),!ye&&fe&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"flex items-center gap-2",children:Se&&Se.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:["匹配成功 (",Se.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(b,{className:"text-sm font-medium",children:"匹配高亮"}),e.jsx(ss,{className:"h-40 rounded-md bg-muted p-3",children:e.jsx("div",{className:"text-sm break-words",children:Ne()})})]}),Object.keys(A).length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"命名捕获组"}),e.jsx(ss,{className:"h-32 rounded-md border p-3",children:e.jsx("div",{className:"space-y-2",children:Object.entries(A).map(([Q,P])=>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:["[",Q,"]"]}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:"font-mono bg-muted px-2 py-0.5 rounded",children:P})]},Q))})})]}),Object.keys(A).length>0&&$&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{className:"text-sm font-medium",children:"Reaction 替换预览"}),e.jsx(ss,{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:E})}),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:"如需修改正则,切换回构建器标签页"})]})]})]})]})})]})]})},S=()=>{h({...n,keyword_rules:[...n.keyword_rules,{keywords:[],reaction:""}]})},k=C=>{h({...n,keyword_rules:n.keyword_rules.filter(($,G)=>G!==C)})},O=(C,$,G)=>{const T=[...n.keyword_rules];typeof G=="string"&&(T[C]={...T[C],reaction:G}),h({...n,keyword_rules:T})},Y=C=>{const $=[...n.keyword_rules];$[C]={...$[C],keywords:[...$[C].keywords||[],""]},h({...n,keyword_rules:$})},L=(C,$)=>{const G=[...n.keyword_rules];G[C]={...G[C],keywords:(G[C].keywords||[]).filter((T,M)=>M!==$)},h({...n,keyword_rules:G})},R=(C,$,G)=>{const T=[...n.keyword_rules],M=[...T[C].keywords||[]];M[$]=G,T[C]={...T[C],keywords:M},h({...n,keyword_rules:T})},H=({rule:C})=>{const $=`{ regex = [${(C.regex||[]).map(G=>`"${G}"`).join(", ")}], reaction = "${C.reaction}" }`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{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(ss,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs break-all",children:$})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},D=({rule:C})=>{const $=`[[keyword_reaction.keyword_rules]] +keywords = [${(C.keywords||[]).map(G=>`"${G}"`).join(", ")}] +reaction = "${C.reaction}"`;return e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",children:[e.jsx(Dt,{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(ss,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs whitespace-pre-wrap break-all",children:$})}),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(N,{onClick:p,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加正则规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[n.regex_rules.map((C,$)=>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:["正则规则 ",$+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(y,{regex:C.regex&&C.regex[0]||"",reaction:C.reaction,onRegexChange:G=>v($,"regex",G),onReactionChange:G=>v($,"reaction",G)}),e.jsx(H,{rule:C}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除正则规则 ",$+1," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>w($),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{className:"text-xs font-medium",children:"正则表达式(Python 语法)"}),e.jsx(ie,{value:C.regex&&C.regex[0]||"",onChange:G=>v($,"regex",G.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(b,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Bs,{value:C.reaction,onChange:G=>v($,"reaction",G.target.value),placeholder:`触发后麦麦的反应... +可以使用 [捕获组名] 来引用正则表达式中的内容`,rows:3,className:"text-sm"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"使用 [捕获组名] 引用正则表达式中的命名捕获组,例如 [n] 会被替换为捕获的内容"})]})]})]},$)),n.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(N,{onClick:S,size:"sm",variant:"outline",children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加关键词规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[n.keyword_rules.map((C,$)=>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:["关键词规则 ",$+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(D,{rule:C}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"sm",variant:"ghost",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除关键词规则 ",$+1," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>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(b,{className:"text-xs font-medium",children:"关键词列表"}),e.jsxs(N,{onClick:()=>Y($),size:"sm",variant:"ghost",children:[e.jsx(ot,{className:"h-3 w-3 mr-1"}),"添加关键词"]})]}),e.jsxs("div",{className:"space-y-2",children:[(C.keywords||[]).map((G,T)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{value:G,onChange:M=>R($,T,M.target.value),placeholder:"关键词",className:"flex-1"}),e.jsx(N,{onClick:()=>L($,T),size:"sm",variant:"ghost",children:e.jsx(ts,{className:"h-4 w-4"})})]},T)),(!C.keywords||C.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(b,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Bs,{value:C.reaction,onChange:G=>O($,"reaction",G.target.value),placeholder:"触发后麦麦的反应...",rows:3,className:"text-sm"})]})]})]},$)),n.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(Qe,{id:"enable_response_post_process",checked:i.enable_response_post_process,onCheckedChange:C=>f({...i,enable_response_post_process:C})}),e.jsx(b,{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(Qe,{id:"enable_chinese_typo",checked:c.enable,onCheckedChange:C=>x({...c,enable:C})}),e.jsx(b,{htmlFor:"enable_chinese_typo",className:"cursor-pointer font-semibold",children:"中文错别字生成器"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mb-4",children:"为回复添加随机错别字,让麦麦的回复更自然"}),c.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(b,{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:c.error_rate,onChange:C=>x({...c,error_rate:parseFloat(C.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"min_freq",className:"text-xs font-medium",children:"最小字频阈值"}),e.jsx(ie,{id:"min_freq",type:"number",min:"0",value:c.min_freq,onChange:C=>x({...c,min_freq:parseInt(C.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{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:c.tone_error_rate,onChange:C=>x({...c,tone_error_rate:parseFloat(C.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{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:c.word_replace_rate,onChange:C=>x({...c,word_replace_rate:parseFloat(C.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(Qe,{id:"enable_response_splitter",checked:d.enable,onCheckedChange:C=>j({...d,enable:C})}),e.jsx(b,{htmlFor:"enable_response_splitter",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(b,{htmlFor:"max_length",className:"text-xs font-medium",children:"最大长度"}),e.jsx(ie,{id:"max_length",type:"number",min:"1",value:d.max_length,onChange:C=>j({...d,max_length:parseInt(C.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"回复允许的最大字符数"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"max_sentence_num",className:"text-xs font-medium",children:"最大句子数"}),e.jsx(ie,{id:"max_sentence_num",type:"number",min:"1",value:d.max_sentence_num,onChange:C=>j({...d,max_sentence_num:parseInt(C.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(Qe,{id:"enable_kaomoji_protection",checked:d.enable_kaomoji_protection,onCheckedChange:C=>j({...d,enable_kaomoji_protection:C})}),e.jsx(b,{htmlFor:"enable_kaomoji_protection",className:"cursor-pointer",children:"启用颜文字保护"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{id:"enable_overflow_return_all",checked:d.enable_overflow_return_all,onCheckedChange:C=>j({...d,enable_overflow_return_all:C})}),e.jsx(b,{htmlFor:"enable_overflow_return_all",className:"cursor-pointer",children:"超出时一次性返回全部"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"当句子数量超出限制时,合并后一次性返回所有内容"})]})]})})]})]})]})}function X0({config:n,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:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{checked:n.enable_mood,onCheckedChange:c=>i({...n,enable_mood:c})}),e.jsx(b,{className:"cursor-pointer",children:"启用情绪系统"})]}),n.enable_mood&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"情绪更新阈值"}),e.jsx(ie,{type:"number",min:"1",value:n.mood_update_threshold,onChange:c=>i({...n,mood_update_threshold:parseInt(c.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"越高,更新越慢"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"情感特征"}),e.jsx(Bs,{value:n.emotion_style,onChange:c=>i({...n,emotion_style:c.target.value}),placeholder:"影响情绪的变化情况",rows:2})]})]})]})]})}function K0({config:n,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(Qe,{checked:n.enable_asr,onCheckedChange:c=>i({...n,enable_asr:c})}),e.jsx(b,{className:"cursor-pointer",children:"启用语音识别"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后麦麦可以识别语音消息,需要配置语音识别模型"})]})}function J0({config:n,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(Qe,{checked:n.enable,onCheckedChange:c=>i({...n,enable:c})}),e.jsx(b,{className:"cursor-pointer",children:"启用 LPMM 知识库"})]}),n.enable&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"LPMM 模式"}),e.jsxs(Be,{value:n.lpmm_mode,onValueChange:c=>i({...n,lpmm_mode:c}),children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"选择 LPMM 模式"})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"classic",children:"经典模式"}),e.jsx(te,{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(b,{children:"同义词搜索 TopK"}),e.jsx(ie,{type:"number",min:"1",value:n.rag_synonym_search_top_k,onChange:c=>i({...n,rag_synonym_search_top_k:parseInt(c.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"同义词阈值"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"1",value:n.rag_synonym_threshold,onChange:c=>i({...n,rag_synonym_threshold:parseFloat(c.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"实体提取线程数"}),e.jsx(ie,{type:"number",min:"1",value:n.info_extraction_workers,onChange:c=>i({...n,info_extraction_workers:parseInt(c.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"嵌入向量维度"}),e.jsx(ie,{type:"number",min:"1",value:n.embedding_dimension,onChange:c=>i({...n,embedding_dimension:parseInt(c.target.value)})})]})]})]})]})]})}function Z0({config:n,onChange:i}){const[c,d]=u.useState(""),[h,f]=u.useState("WARNING"),x=()=>{c&&!n.suppress_libraries.includes(c)&&(i({...n,suppress_libraries:[...n.suppress_libraries,c]}),d(""))},j=k=>{i({...n,suppress_libraries:n.suppress_libraries.filter(O=>O!==k)})},p=()=>{c&&!n.library_log_levels[c]&&(i({...n,library_log_levels:{...n.library_log_levels,[c]:h}}),d(""),f("WARNING"))},w=k=>{const O={...n.library_log_levels};delete O[k],i({...n,library_log_levels:O})},v=["DEBUG","INFO","WARNING","ERROR","CRITICAL"],y=["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(b,{children:"日期格式"}),e.jsx(ie,{value:n.date_style,onChange:k=>i({...n,date_style:k.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(b,{children:"日志级别样式"}),e.jsxs(Be,{value:n.log_level_style,onValueChange:k=>i({...n,log_level_style:k}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:y.map(k=>e.jsx(te,{value:k,children:k},k))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"日志文本颜色"}),e.jsxs(Be,{value:n.color_text,onValueChange:k=>i({...n,color_text:k}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:S.map(k=>e.jsx(te,{value:k,children:k},k))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"全局日志级别"}),e.jsxs(Be,{value:n.log_level,onValueChange:k=>i({...n,log_level:k}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:v.map(k=>e.jsx(te,{value:k,children:k},k))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"控制台日志级别"}),e.jsxs(Be,{value:n.console_log_level,onValueChange:k=>i({...n,console_log_level:k}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:v.map(k=>e.jsx(te,{value:k,children:k},k))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"文件日志级别"}),e.jsxs(Be,{value:n.file_log_level,onValueChange:k=>i({...n,file_log_level:k}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsx(Ue,{children:v.map(k=>e.jsx(te,{value:k,children:k},k))})]})]})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"mb-2 block",children:"完全屏蔽的库"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:c,onChange:k=>d(k.target.value),placeholder:"输入库名",className:"flex-1",onKeyDown:k=>{k.key==="Enter"&&(k.preventDefault(),x())}}),e.jsx(N,{onClick:x,size:"sm",className:"flex-shrink-0",children:e.jsx(ot,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:n.suppress_libraries.map(k=>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:k}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0",onClick:()=>j(k),children:e.jsx(ts,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},k))})]}),e.jsxs("div",{children:[e.jsx(b,{className:"mb-2 block",children:"特定库的日志级别"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:c,onChange:k=>d(k.target.value),placeholder:"输入库名",className:"flex-1"}),e.jsxs(Be,{value:h,onValueChange:f,children:[e.jsx(Le,{className:"w-32",children:e.jsx(He,{})}),e.jsx(Ue,{children:v.map(k=>e.jsx(te,{value:k,children:k},k))})]}),e.jsx(N,{onClick:p,size:"sm",children:e.jsx(ot,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:Object.entries(n.library_log_levels).map(([k,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:k}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm text-muted-foreground",children:O}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>w(k),children:e.jsx(ts,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]})]},k))})]})]})}function I0({config:n,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(b,{children:"显示 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否在日志中显示提示词"})]}),e.jsx(Qe,{checked:n.show_prompt,onCheckedChange:c=>i({...n,show_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示回复器 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的提示词"})]}),e.jsx(Qe,{checked:n.show_replyer_prompt,onCheckedChange:c=>i({...n,show_replyer_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示回复器推理"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的推理过程"})]}),e.jsx(Qe,{checked:n.show_replyer_reasoning,onCheckedChange:c=>i({...n,show_replyer_reasoning:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示 Jargon Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示术语相关的提示词"})]}),e.jsx(Qe,{checked:n.show_jargon_prompt,onCheckedChange:c=>i({...n,show_jargon_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示记忆检索 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示记忆检索相关的提示词"})]}),e.jsx(Qe,{checked:n.show_memory_prompt,onCheckedChange:c=>i({...n,show_memory_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示 Planner Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 Planner 的提示词和原始返回结果"})]}),e.jsx(Qe,{checked:n.show_planner_prompt,onCheckedChange:c=>i({...n,show_planner_prompt:c})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{children:"显示 LPMM 相关文段"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 LPMM 知识库找到的相关文段日志"})]}),e.jsx(Qe,{checked:n.show_lpmm_paragraph,onCheckedChange:c=>i({...n,show_lpmm_paragraph:c})})]})]})]})}function P0({config:n,onChange:i}){const[c,d]=u.useState(""),h=()=>{c&&!n.auth_token.includes(c)&&(i({...n,auth_token:[...n.auth_token,c]}),d(""))},f=x=>{i({...n,auth_token:n.auth_token.filter((j,p)=>p!==x)})};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(b,{children:"启用自定义服务器"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否使用自定义的 MaimMessage 服务器"})]}),e.jsx(Qe,{checked:n.use_custom,onCheckedChange:x=>i({...n,use_custom:x})})]}),n.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(b,{children:"主机地址"}),e.jsx(ie,{value:n.host,onChange:x=>i({...n,host:x.target.value}),placeholder:"127.0.0.1"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"端口号"}),e.jsx(ie,{type:"number",value:n.port,onChange:x=>i({...n,port:parseInt(x.target.value)}),placeholder:"8090"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"连接模式"}),e.jsxs(Be,{value:n.mode,onValueChange:x=>i({...n,mode:x}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"ws",children:"WebSocket (ws)"}),e.jsx(te,{value:"tcp",children:"TCP"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{checked:n.use_wss,onCheckedChange:x=>i({...n,use_wss:x}),disabled:n.mode!=="ws"}),e.jsx(b,{children:"使用 WSS 安全连接"})]})]}),n.use_wss&&n.mode==="ws"&&e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"SSL 证书文件路径"}),e.jsx(ie,{value:n.cert_file,onChange:x=>i({...n,cert_file:x.target.value}),placeholder:"cert.pem"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"SSL 密钥文件路径"}),e.jsx(ie,{value:n.key_file,onChange:x=>i({...n,key_file:x.target.value}),placeholder:"key.pem"})]})]})]})]})]}),e.jsxs("div",{children:[e.jsx(b,{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:c,onChange:x=>d(x.target.value),placeholder:"输入认证令牌",onKeyDown:x=>{x.key==="Enter"&&(x.preventDefault(),h())}}),e.jsx(N,{onClick:h,size:"sm",children:e.jsx(ot,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:n.auth_token.map((x,j)=>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:x}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>f(j),children:e.jsx(ts,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},j))})]})]})}function W0({config:n,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(b,{children:"启用统计信息发送"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"发送匿名统计信息,帮助我们了解全球有多少只麦麦在运行"})]}),e.jsx(Qe,{checked:n.enable,onCheckedChange:c=>i({...n,enable:c})})]})]})}const hn=u.forwardRef(({className:n,...i},c)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:c,className:X("w-full caption-bottom text-sm",n),...i})}));hn.displayName="Table";const xn=u.forwardRef(({className:n,...i},c)=>e.jsx("thead",{ref:c,className:X("[&_tr]:border-b",n),...i}));xn.displayName="TableHeader";const fn=u.forwardRef(({className:n,...i},c)=>e.jsx("tbody",{ref:c,className:X("[&_tr:last-child]:border-0",n),...i}));fn.displayName="TableBody";const ew=u.forwardRef(({className:n,...i},c)=>e.jsx("tfoot",{ref:c,className:X("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",n),...i}));ew.displayName="TableFooter";const dt=u.forwardRef(({className:n,...i},c)=>e.jsx("tr",{ref:c,className:X("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",n),...i}));dt.displayName="TableRow";const Ie=u.forwardRef(({className:n,...i},c)=>e.jsx("th",{ref:c,className:X("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",n),...i}));Ie.displayName="TableHead";const Fe=u.forwardRef(({className:n,...i},c)=>e.jsx("td",{ref:c,className:X("px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",n),...i}));Fe.displayName="TableCell";const sw=u.forwardRef(({className:n,...i},c)=>e.jsx("caption",{ref:c,className:X("mt-4 text-sm text-muted-foreground",n),...i}));sw.displayName="TableCaption";const no=u.forwardRef(({className:n,...i},c)=>e.jsx(Qt,{ref:c,className:X("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",n),...i}));no.displayName=Qt.displayName;const io=u.forwardRef(({className:n,...i},c)=>e.jsxs("div",{className:"flex items-center border-b px-3","cmdk-input-wrapper":"",children:[e.jsx(zt,{className:"mr-2 h-4 w-4 shrink-0 opacity-50"}),e.jsx(Qt.Input,{ref:c,className:X("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),...i})]}));io.displayName=Qt.Input.displayName;const ro=u.forwardRef(({className:n,...i},c)=>e.jsx(Qt.List,{ref:c,className:X("max-h-[300px] overflow-y-auto overflow-x-hidden",n),...i}));ro.displayName=Qt.List.displayName;const co=u.forwardRef((n,i)=>e.jsx(Qt.Empty,{ref:i,className:"py-6 text-center text-sm",...n}));co.displayName=Qt.Empty.displayName;const vr=u.forwardRef(({className:n,...i},c)=>e.jsx(Qt.Group,{ref:c,className:X("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),...i}));vr.displayName=Qt.Group.displayName;const tw=u.forwardRef(({className:n,...i},c)=>e.jsx(Qt.Separator,{ref:c,className:X("-mx-1 h-px bg-border",n),...i}));tw.displayName=Qt.Separator.displayName;const Nr=u.forwardRef(({className:n,...i},c)=>e.jsx(Qt.Item,{ref:c,className:X("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),...i}));Nr.displayName=Qt.Item.displayName;const jt=u.forwardRef(({className:n,...i},c)=>e.jsx(eg,{ref:c,className:X("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),...i,children:e.jsx(ib,{className:X("grid place-content-center text-current"),children:e.jsx($t,{className:"h-4 w-4"})})}));jt.displayName=eg.displayName;const Dg=u.createContext(null),Og="maibot-completed-tours";function aw(){try{const n=localStorage.getItem(Og);return n?new Set(JSON.parse(n)):new Set}catch{return new Set}}function dp(n){localStorage.setItem(Og,JSON.stringify([...n]))}function lw({children:n}){const[i,c]=u.useState({activeTourId:null,stepIndex:0,isRunning:!1}),d=u.useRef(new Map),[,h]=u.useState(0),[f,x]=u.useState(aw),j=u.useCallback((D,C)=>{d.current.set(D,C),h($=>$+1)},[]),p=u.useCallback(D=>{d.current.delete(D),c(C=>C.activeTourId===D?{...C,activeTourId:null,isRunning:!1,stepIndex:0}:C)},[]),w=u.useCallback((D,C=0)=>{d.current.has(D)&&c({activeTourId:D,stepIndex:C,isRunning:!0})},[]),v=u.useCallback(()=>{c(D=>({...D,isRunning:!1}))},[]),y=u.useCallback(D=>{c(C=>({...C,stepIndex:D}))},[]),S=u.useCallback(()=>{c(D=>({...D,stepIndex:D.stepIndex+1}))},[]),k=u.useCallback(()=>{c(D=>({...D,stepIndex:Math.max(0,D.stepIndex-1)}))},[]),O=u.useCallback(()=>i.activeTourId?d.current.get(i.activeTourId)||[]:[],[i.activeTourId]),Y=u.useCallback(D=>{x(C=>{const $=new Set(C);return $.add(D),dp($),$})},[]),L=u.useCallback(D=>{const{action:C,index:$,status:G,type:T}=D,M=["finished","skipped"];if(C==="close"){c(ne=>({...ne,isRunning:!1,stepIndex:0}));return}M.includes(G)?c(ne=>(G==="finished"&&ne.activeTourId&&setTimeout(()=>Y(ne.activeTourId),0),{...ne,isRunning:!1,stepIndex:0})):T==="step:after"&&(C==="next"?c(ne=>({...ne,stepIndex:$+1})):C==="prev"&&c(ne=>({...ne,stepIndex:$-1})))},[Y]),R=u.useCallback(D=>f.has(D),[f]),H=u.useCallback(D=>{x(C=>{const $=new Set(C);return $.delete(D),dp($),$})},[]);return e.jsx(Dg.Provider,{value:{state:i,tours:d.current,registerTour:j,unregisterTour:p,startTour:w,stopTour:v,goToStep:y,nextStep:S,prevStep:k,getCurrentSteps:O,handleJoyrideCallback:L,isTourCompleted:R,markTourCompleted:Y,resetTourCompleted:H},children:n})}function Wu(){const n=u.useContext(Dg);if(!n)throw new Error("useTour must be used within a TourProvider");return n}const nw={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)"}},iw={back:"上一步",close:"关闭",last:"完成",next:"下一步",nextLabelWithProgress:"下一步 ({step}/{steps})",open:"打开对话框",skip:"跳过"};function rw(){const{state:n,getCurrentSteps:i,handleJoyrideCallback:c}=Wu(),d=i(),[h,f]=u.useState(!1),x=u.useRef(n.stepIndex),j=u.useRef(null);u.useEffect(()=>{x.current!==n.stepIndex&&(f(!1),x.current=n.stepIndex)},[n.stepIndex]),u.useEffect(()=>{if(!n.isRunning||d.length===0){f(!1);return}const v=d[n.stepIndex];if(!v){f(!1);return}const y=v.target;if(y==="body"){f(!0);return}f(!1);const S=setTimeout(()=>{const k=()=>{const R=document.querySelector(y);if(R){const H=R.getBoundingClientRect();if(H.width>0&&H.height>0)return!0}return!1};if(k()){setTimeout(()=>f(!0),100);return}const O=setInterval(()=>{k()&&(clearInterval(O),setTimeout(()=>f(!0),100))},100),Y=setTimeout(()=>{clearInterval(O),f(!0)},5e3),L=()=>{clearInterval(O),clearTimeout(Y)};j.current=L},150);return()=>{clearTimeout(S),j.current&&(j.current(),j.current=null)}},[n.isRunning,n.stepIndex,d]);const p=u.useRef(null);if(u.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)),p.current=v,()=>{}},[]),!n.isRunning||d.length===0||!h)return null;const w=e.jsx(Zb,{steps:d,stepIndex:n.stepIndex,run:n.isRunning,continuous:!0,showSkipButton:!0,showProgress:!0,disableOverlayClose:!0,disableScrolling:!1,disableScrollParentFix:!1,callback:c,styles:nw,locale:iw,scrollOffset:80,scrollToFirstStep:!0,floaterProps:{styles:{floater:{zIndex:99999}},disableAnimation:!0}},`tour-step-${n.stepIndex}`);return p.current?cN.createPortal(w,p.current):w}const il="model-assignment-tour",Rg=[{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}],Lg={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"},or=[{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 up(n){return n?n.replace(/\/+$/,"").toLowerCase():""}function cw(n){if(!n)return null;const i=up(n);return or.find(c=>c.id!=="custom"&&up(c.base_url)===i)||null}function ow(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,f]=u.useState(!1),[x,j]=u.useState(!1),[p,w]=u.useState(!1),[v,y]=u.useState(!1),[S,k]=u.useState(!1),[O,Y]=u.useState(!1),[L,R]=u.useState(null),[H,D]=u.useState(null),[C,$]=u.useState("custom"),[G,T]=u.useState(!1),[M,ne]=u.useState(!1),[fe,_e]=u.useState(null),[Se,je]=u.useState(!1),[ye,be]=u.useState(""),[A,K]=u.useState(new Set),[E,se]=u.useState(!1),[_,me]=u.useState(1),[re,le]=u.useState(20),[pe,Ne]=u.useState(""),[he,Q]=u.useState({}),[P,q]=u.useState(new Set),[W,Ce]=u.useState(new Map),{toast:Me}=Vs(),ce=ja(),{state:De,goToStep:Fs,registerTour:Qs}=Wu(),ue=u.useRef(null),Ee=u.useRef(!0);u.useEffect(()=>{Qs(il,Rg)},[Qs]),u.useEffect(()=>{if(De.activeTourId===il&&De.isRunning){const ee=Lg[De.stepIndex];ee&&!window.location.pathname.endsWith(ee.replace("/config/",""))&&ce({to:ee})}},[De.stepIndex,De.activeTourId,De.isRunning,ce]);const as=u.useRef(De.stepIndex);u.useEffect(()=>{if(De.activeTourId===il&&De.isRunning){const ee=as.current,we=De.stepIndex;ee>=3&&ee<=9&&we<3&&Y(!1),ee>=10&&we>=3&&we<=9&&(Q({}),$("custom"),R({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10}),D(null),je(!1),Y(!0)),as.current=we}},[De.stepIndex,De.activeTourId,De.isRunning]),u.useEffect(()=>{if(De.activeTourId!==il||!De.isRunning)return;const ee=we=>{const Ve=we.target,pt=De.stepIndex;pt===2&&Ve.closest('[data-tour="add-provider-button"]')?setTimeout(()=>Fs(3),300):pt===9&&Ve.closest('[data-tour="provider-cancel-button"]')&&setTimeout(()=>Fs(10),300)};return document.addEventListener("click",ee,!0),()=>document.removeEventListener("click",ee,!0)},[De,Fs]),u.useEffect(()=>{Ke()},[]);const Ke=async()=>{try{d(!0);const ee=await ni();i(ee.api_providers||[]),w(!1),Ee.current=!1}catch(ee){console.error("加载配置失败:",ee)}finally{d(!1)}},lt=async()=>{try{y(!0),lo().catch(()=>{}),k(!0)}catch(ee){console.error("重启失败:",ee),k(!1),Me({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),y(!1)}},Ot=async()=>{try{f(!0),ue.current&&clearTimeout(ue.current);const ee=await ni();ee.api_providers=n,await to(ee),w(!1),Me({title:"保存成功",description:"正在重启麦麦..."}),await lt()}catch(ee){console.error("保存配置失败:",ee),Me({title:"保存失败",description:ee.message,variant:"destructive"}),f(!1)}},bt=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},Pe=()=>{k(!1),y(!1),Me({title:"重启超时",description:"服务未能在预期时间内恢复,请手动检查或刷新页面",variant:"destructive"})},U=u.useCallback(async ee=>{if(!Ee.current)try{j(!0),await qu("api_providers",ee),w(!1)}catch(we){console.error("自动保存失败:",we),w(!0)}finally{j(!1)}},[]);u.useEffect(()=>{if(!Ee.current)return w(!0),ue.current&&clearTimeout(ue.current),ue.current=setTimeout(()=>{U(n)},2e3),()=>{ue.current&&clearTimeout(ue.current)}},[n,U]);const Re=async()=>{try{f(!0),ue.current&&clearTimeout(ue.current);const ee=await ni();ee.api_providers=n,await to(ee),w(!1),Me({title:"保存成功",description:"模型提供商配置已保存"})}catch(ee){console.error("保存配置失败:",ee),Me({title:"保存失败",description:ee.message,variant:"destructive"})}finally{f(!1)}},ze=(ee,we)=>{if(Q({}),ee){const Ve=or.find(pt=>pt.base_url===ee.base_url&&pt.client_type===ee.client_type);$(Ve?.id||"custom"),R(ee)}else $("custom"),R({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10});D(we),je(!1),Y(!0)},Ye=ee=>{$(ee),T(!1);const we=or.find(Ve=>Ve.id===ee);we&&we.id!=="custom"?R(Ve=>({...Ve,name:we.name,base_url:we.base_url,client_type:we.client_type})):we?.id==="custom"&&R(Ve=>({...Ve,name:"",base_url:"",client_type:"openai"}))},zs=u.useMemo(()=>C!=="custom",[C]),We=async()=>{if(L?.api_key)try{await navigator.clipboard.writeText(L.api_key),Me({title:"复制成功",description:"API Key 已复制到剪贴板"})}catch{Me({title:"复制失败",description:"无法访问剪贴板",variant:"destructive"})}},nt=()=>{if(!L)return;const ee={};if(L.name?.trim()||(ee.name="请输入提供商名称"),L.base_url?.trim()||(ee.base_url="请输入基础 URL"),L.api_key?.trim()||(ee.api_key="请输入 API Key"),Object.keys(ee).length>0){Q(ee);return}Q({});const we={...L,max_retry:L.max_retry??2,timeout:L.timeout??30,retry_interval:L.retry_interval??10};if(H!==null){const Ve=[...n];Ve[H]=we,i(Ve)}else i([...n,we]);Y(!1),R(null),D(null)},vs=ee=>{if(!ee&&L){const we={...L,max_retry:L.max_retry??2,timeout:L.timeout??30,retry_interval:L.retry_interval??10};R(we)}Y(ee)},ke=ee=>{_e(ee),ne(!0)},ve=()=>{if(fe!==null){const ee=n.filter((we,Ve)=>Ve!==fe);i(ee),Me({title:"删除成功",description:"提供商已从列表中移除"})}ne(!1),_e(null)},is=ee=>{const we=new Set(A);we.has(ee)?we.delete(ee):we.add(ee),K(we)},_s=()=>{if(A.size===Ys.length)K(new Set);else{const ee=Ys.map((we,Ve)=>n.findIndex(pt=>pt===Ys[Ve]));K(new Set(ee))}},At=()=>{if(A.size===0){Me({title:"提示",description:"请先选择要删除的提供商",variant:"default"});return}se(!0)},Ps=()=>{const ee=n.filter((we,Ve)=>!A.has(Ve));i(ee),K(new Set),se(!1),Me({title:"批量删除成功",description:`已删除 ${A.size} 个提供商`})},Ys=n.filter(ee=>{if(!ye)return!0;const we=ye.toLowerCase();return ee.name.toLowerCase().includes(we)||ee.base_url.toLowerCase().includes(we)||ee.client_type.toLowerCase().includes(we)}),Et=Math.ceil(Ys.length/re),Rt=Ys.slice((_-1)*re,_*re),Ha=()=>{const ee=parseInt(pe);ee>=1&&ee<=Et&&(me(ee),Ne(""))},Yt=async ee=>{q(we=>new Set(we).add(ee));try{const we=await D0(ee);Ce(Ve=>new Map(Ve).set(ee,we)),we.network_ok?we.api_key_valid===!0?Me({title:"连接正常",description:`${ee} 网络连接正常,API Key 有效 (${we.latency_ms}ms)`}):we.api_key_valid===!1?Me({title:"连接正常但 Key 无效",description:`${ee} 网络连接正常,但 API Key 无效或已过期`,variant:"destructive"}):Me({title:"网络连接正常",description:`${ee} 可以访问 (${we.latency_ms}ms)`}):Me({title:"连接失败",description:we.error||"无法连接到提供商",variant:"destructive"})}catch(we){Me({title:"测试失败",description:we.message,variant:"destructive"})}finally{q(we=>{const Ve=new Set(we);return Ve.delete(ee),Ve})}},qa=async()=>{for(const ee of n)await Yt(ee.name)},Ta=ee=>{const we=P.has(ee),Ve=W.get(ee);return we?e.jsxs($e,{variant:"secondary",className:"gap-1",children:[e.jsx(kt,{className:"h-3 w-3 animate-spin"}),"测试中"]}):Ve?Ve.network_ok?Ve.api_key_valid===!0?e.jsxs($e,{className:"gap-1 bg-green-600 hover:bg-green-700",children:[e.jsx(fa,{className:"h-3 w-3"}),"正常"]}):Ve.api_key_valid===!1?e.jsxs($e,{variant:"destructive",className:"gap-1",children:[e.jsx(Sa,{className:"h-3 w-3"}),"Key无效"]}):e.jsxs($e,{className:"gap-1 bg-blue-600 hover:bg-blue-700",children:[e.jsx(fa,{className:"h-3 w-3"}),"可访问"]}):e.jsxs($e,{variant:"destructive",className:"gap-1",children:[e.jsx(cg,{className:"h-3 w-3"}),"离线"]}):null};return c?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:[A.size>0&&e.jsxs(N,{onClick:At,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(ts,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",A.size,")"]}),e.jsxs(N,{onClick:qa,size:"sm",variant:"outline",className:"w-full sm:w-auto",disabled:n.length===0||P.size>0,children:[e.jsx(cn,{className:"mr-2 h-4 w-4"}),P.size>0?`测试中 (${P.size})`:"测试全部"]}),e.jsxs(N,{onClick:()=>ze(null,null),size:"sm",className:"w-full sm:w-auto","data-tour":"add-provider-button",children:[e.jsx(ot,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"添加提供商"]}),e.jsxs(N,{onClick:Re,disabled:h||x||!p||v,size:"sm",variant:"outline",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(yr,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),h?"保存中...":x?"自动保存中...":p?"保存配置":"已保存"]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{disabled:h||x||v,size:"sm",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(br,{className:"mr-2 h-4 w-4"}),v?"重启中...":p?"保存并重启":"重启麦麦"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认重启麦麦?"}),e.jsx(us,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:p?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:p?Ot:lt,children:p?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(cl,{children:[e.jsx(La,{className:"h-4 w-4"}),e.jsxs(ol,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(ss,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索提供商名称、URL 或类型...",value:ye,onChange:ee=>be(ee.target.value),className:"pl-9"})]}),ye&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Ys.length," 个结果"]})]}),e.jsx("div",{className:"md:hidden space-y-3",children:Ys.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 rounded-lg border bg-card",children:ye?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'}):Rt.map((ee,we)=>{const Ve=n.findIndex(pt=>pt===ee);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:ee.name}),Ta(ee.name)]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 break-all",children:ee.base_url})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>Yt(ee.name),disabled:P.has(ee.name),title:"测试连接",children:P.has(ee.name)?e.jsx(kt,{className:"h-4 w-4 animate-spin"}):e.jsx(cn,{className:"h-4 w-4"})}),e.jsx(N,{variant:"default",size:"sm",onClick:()=>ze(ee,Ve),children:e.jsx(on,{className:"h-4 w-4",strokeWidth:2,fill:"none"})}),e.jsx(N,{size:"sm",onClick:()=>ke(Ve),className:"bg-red-600 hover:bg-red-700 text-white",children:e.jsx(ts,{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:ee.client_type})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"最大重试"}),e.jsx("p",{className:"font-medium",children:ee.max_retry})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"超时(秒)"}),e.jsx("p",{className:"font-medium",children:ee.timeout})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"重试间隔(秒)"}),e.jsx("p",{className:"font-medium",children:ee.retry_interval})]})]})]},we)})}),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(hn,{children:[e.jsx(xn,{children:e.jsxs(dt,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:A.size===Ys.length&&Ys.length>0,onCheckedChange:_s})}),e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{children:"名称"}),e.jsx(Ie,{children:"基础URL"}),e.jsx(Ie,{children:"客户端类型"}),e.jsx(Ie,{className:"text-right",children:"最大重试"}),e.jsx(Ie,{className:"text-right",children:"超时(秒)"}),e.jsx(Ie,{className:"text-right",children:"重试间隔(秒)"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:Rt.length===0?e.jsx(dt,{children:e.jsx(Fe,{colSpan:9,className:"text-center text-muted-foreground py-8",children:ye?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'})}):Rt.map((ee,we)=>{const Ve=n.findIndex(pt=>pt===ee);return e.jsxs(dt,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:A.has(Ve),onCheckedChange:()=>is(Ve)})}),e.jsx(Fe,{children:Ta(ee.name)||e.jsx($e,{variant:"outline",className:"text-muted-foreground",children:"未测试"})}),e.jsx(Fe,{className:"font-medium",children:ee.name}),e.jsx(Fe,{className:"max-w-xs truncate",title:ee.base_url,children:ee.base_url}),e.jsx(Fe,{children:ee.client_type}),e.jsx(Fe,{className:"text-right",children:ee.max_retry}),e.jsx(Fe,{className:"text-right",children:ee.timeout}),e.jsx(Fe,{className:"text-right",children:ee.retry_interval}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>Yt(ee.name),disabled:P.has(ee.name),title:"测试连接",children:P.has(ee.name)?e.jsx(kt,{className:"h-4 w-4 animate-spin"}):e.jsx(cn,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"default",size:"sm",onClick:()=>ze(ee,Ve),children:[e.jsx(on,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>ke(Ve),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ts,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},we)})})]})})}),Ys.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(b,{htmlFor:"page-size-provider",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Be,{value:re.toString(),onValueChange:ee=>{le(parseInt(ee)),me(1),K(new Set)},children:[e.jsx(Le,{id:"page-size-provider",className:"w-20",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"10",children:"10"}),e.jsx(te,{value:"20",children:"20"}),e.jsx(te,{value:"50",children:"50"}),e.jsx(te,{value:"100",children:"100"})]})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["显示 ",(_-1)*re+1," 到"," ",Math.min(_*re,Ys.length)," 条,共 ",Ys.length," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>me(1),disabled:_===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>me(ee=>Math.max(1,ee-1)),disabled:_===1,children:[e.jsx(Hl,{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:pe,onChange:ee=>Ne(ee.target.value),onKeyDown:ee=>ee.key==="Enter"&&Ha(),placeholder:_.toString(),className:"w-16 h-8 text-center",min:1,max:Et}),e.jsx(N,{variant:"outline",size:"sm",onClick:Ha,disabled:!pe,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>me(ee=>ee+1),disabled:_>=Et,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>me(Et),disabled:_>=Et,className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]}),e.jsx($s,{open:O,onOpenChange:vs,children:e.jsxs(Hs,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"provider-dialog",preventOutsideClose:De.isRunning,children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:H!==null?"编辑提供商":"添加提供商"}),e.jsx(Is,{children:"配置 API 提供商的连接信息和参数"})]}),e.jsxs("form",{onSubmit:ee=>{ee.preventDefault(),nt()},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(b,{htmlFor:"template",children:"提供商模板"}),e.jsxs(Ua,{open:G,onOpenChange:T,children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",role:"combobox","aria-expanded":G,className:"w-full justify-between",children:[C?or.find(ee=>ee.id===C)?.display_name:"选择提供商模板...",e.jsx(Yu,{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(no,{children:[e.jsx(io,{placeholder:"搜索提供商模板..."}),e.jsx(ss,{className:"h-[300px]",children:e.jsxs(ro,{className:"max-h-none overflow-visible",children:[e.jsx(co,{children:"未找到匹配的模板"}),e.jsx(vr,{children:or.map(ee=>e.jsxs(Nr,{value:ee.display_name,onSelect:()=>Ye(ee.id),children:[e.jsx($t,{className:`mr-2 h-4 w-4 ${C===ee.id?"opacity-100":"opacity-0"}`}),ee.display_name]},ee.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(b,{htmlFor:"name",className:he.name?"text-destructive":"",children:"名称 *"}),e.jsx(ie,{id:"name",value:L?.name||"",onChange:ee=>{R(we=>we?{...we,name:ee.target.value}:null),he.name&&Q(we=>({...we,name:void 0}))},placeholder:"例如: DeepSeek, SiliconFlow",className:he.name?"border-destructive focus-visible:ring-destructive":""}),he.name&&e.jsx("p",{className:"text-xs text-destructive",children:he.name})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-url-input",children:[e.jsx(b,{htmlFor:"base_url",className:he.base_url?"text-destructive":"",children:"基础 URL *"}),e.jsx(ie,{id:"base_url",value:L?.base_url||"",onChange:ee=>{R(we=>we?{...we,base_url:ee.target.value}:null),he.base_url&&Q(we=>({...we,base_url:void 0}))},placeholder:"https://api.example.com/v1",disabled:zs,className:`${zs?"bg-muted cursor-not-allowed":""} ${he.base_url?"border-destructive focus-visible:ring-destructive":""}`}),he.base_url&&e.jsx("p",{className:"text-xs text-destructive",children:he.base_url}),zs&&!he.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(b,{htmlFor:"api_key",className:he.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:L?.api_key||"",onChange:ee=>{R(we=>we?{...we,api_key:ee.target.value}:null),he.api_key&&Q(we=>({...we,api_key:void 0}))},placeholder:"sk-...",className:`flex-1 ${he.api_key?"border-destructive focus-visible:ring-destructive":""}`}),e.jsx(N,{type:"button",variant:"outline",size:"icon",onClick:()=>je(!Se),title:Se?"隐藏密钥":"显示密钥",children:Se?e.jsx(xr,{className:"h-4 w-4"}):e.jsx(Dt,{className:"h-4 w-4"})}),e.jsx(N,{type:"button",variant:"outline",size:"icon",onClick:We,title:"复制密钥",children:e.jsx(Pc,{className:"h-4 w-4"})})]}),he.api_key&&e.jsx("p",{className:"text-xs text-destructive",children:he.api_key})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"client_type",children:"客户端类型"}),e.jsxs(Be,{value:L?.client_type||"openai",onValueChange:ee=>R(we=>we?{...we,client_type:ee}:null),disabled:zs,children:[e.jsx(Le,{id:"client_type",className:zs?"bg-muted cursor-not-allowed":"",children:e.jsx(He,{placeholder:"选择客户端类型"})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"openai",children:"OpenAI"}),e.jsx(te,{value:"gemini",children:"Gemini"})]})]}),zs&&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(b,{htmlFor:"max_retry",children:"最大重试"}),e.jsx(ie,{id:"max_retry",type:"number",min:"0",value:L?.max_retry??"",onChange:ee=>{const we=ee.target.value===""?null:parseInt(ee.target.value);R(Ve=>Ve?{...Ve,max_retry:we}:null)},placeholder:"默认: 2"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"timeout",children:"超时(秒)"}),e.jsx(ie,{id:"timeout",type:"number",min:"1",value:L?.timeout??"",onChange:ee=>{const we=ee.target.value===""?null:parseInt(ee.target.value);R(Ve=>Ve?{...Ve,timeout:we}:null)},placeholder:"默认: 30"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"retry_interval",children:"重试间隔(秒)"}),e.jsx(ie,{id:"retry_interval",type:"number",min:"1",value:L?.retry_interval??"",onChange:ee=>{const we=ee.target.value===""?null:parseInt(ee.target.value);R(Ve=>Ve?{...Ve,retry_interval:we}:null)},placeholder:"默认: 10"})]})]})]}),e.jsxs(at,{children:[e.jsx(N,{type:"button",variant:"outline",onClick:()=>Y(!1),"data-tour":"provider-cancel-button",children:"取消"}),e.jsx(N,{type:"submit","data-tour":"provider-save-button",children:"保存"})]})]})]})}),e.jsx(ps,{open:M,onOpenChange:ne,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除提供商 "',fe!==null?n[fe]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:ve,children:"删除"})]})]})}),e.jsx(ps,{open:E,onOpenChange:se,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认批量删除"}),e.jsxs(us,{children:["确定要删除选中的 ",A.size," 个提供商吗? 此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:Ps,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),S&&e.jsx(Pu,{onRestartComplete:bt,onRestartFailed:Pe})]})}function dw({value:n,label:i,onRemove:c}){const{attributes:d,listeners:h,setNodeRef:f,transform:x,transition:j,isDragging:p}=ry({id:n}),w={transform:cy.Transform.toString(x),transition:j,opacity:p?.5:1},v=S=>{S.preventDefault(),S.stopPropagation(),c(n)},y=S=>{S.stopPropagation()};return e.jsx("div",{ref:f,style:w,className:X("inline-flex items-center gap-1",p&&"shadow-lg"),children:e.jsxs($e,{variant:"secondary",className:"cursor-move hover:bg-secondary/80 flex items-center gap-1",children:[e.jsx("div",{...d,...h,className:"cursor-grab active:cursor-grabbing flex items-center",children:e.jsx(Sb,{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:S=>S.stopPropagation(),children:e.jsx(dl,{className:"h-3 w-3 cursor-pointer hover:text-destructive",strokeWidth:2,fill:"none"})})]})})}function uw({options:n,selected:i,onChange:c,placeholder:d="选择选项...",emptyText:h="未找到选项",className:f}){const[x,j]=u.useState(!1),p=Pb(Pf(iy,{activationConstraint:{distance:8}}),Pf(ny,{coordinateGetter:ly})),w=S=>{i.includes(S)?c(i.filter(k=>k!==S)):c([...i,S])},v=S=>{c(i.filter(k=>k!==S))},y=S=>{const{active:k,over:O}=S;if(O&&k.id!==O.id){const Y=i.indexOf(k.id),L=i.indexOf(O.id);c(ay(i,Y,L))}};return e.jsxs(Ua,{open:x,onOpenChange:j,children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",role:"combobox","aria-expanded":x,className:X("w-full justify-between min-h-10 h-auto",f),children:[e.jsx(Wb,{sensors:p,collisionDetection:ey,onDragEnd:y,children:e.jsx(sy,{items:i,strategy:ty,children:e.jsx("div",{className:"flex gap-1 flex-wrap flex-1",children:i.length===0?e.jsx("span",{className:"text-muted-foreground",children:d}):i.map(S=>{const k=n.find(O=>O.value===S);return e.jsx(dw,{value:S,label:k?.label||S,onRemove:v},S)})})})}),e.jsx(Yu,{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(no,{children:[e.jsx(io,{placeholder:"搜索...",className:"h-9"}),e.jsxs(ro,{children:[e.jsx(co,{children:h}),e.jsx(vr,{children:n.map(S=>{const k=i.includes(S.value);return e.jsxs(Nr,{value:S.value,onSelect:()=>w(S.value),children:[e.jsx("div",{className:X("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($t,{className:"h-3 w-3",strokeWidth:2,fill:"none"})}),e.jsx("span",{children:S.label})]},S.value)})})]})]})})]})}function Ug(n){return typeof n=="boolean"?"boolean":typeof n=="number"?"number":"string"}function mw(n,i){switch(i){case"boolean":return n==="true";case"number":{const c=parseFloat(n);return isNaN(c)?0:c}default:return n}}function zu(n){return Object.entries(n).map(([i,c])=>({id:crypto.randomUUID(),key:i,value:c,type:Ug(c)}))}function Au(n){const i={};for(const c of n)c.key.trim()&&(i[c.key.trim()]=c.value);return i}function Mu(n){if(!n.trim())return{valid:!0,parsed:{}};try{const i=JSON.parse(n);if(typeof i!="object"||i===null||Array.isArray(i))return{valid:!1,error:"必须是一个 JSON 对象 {}"};for(const[c,d]of Object.entries(i))if(d!==null&&!["string","number","boolean"].includes(typeof d))return{valid:!1,error:`键 "${c}" 的值类型不支持(仅支持 string/number/boolean)`};return{valid:!0,parsed:i}}catch{return{valid:!1,error:"JSON 格式错误"}}}function hw(n){switch(n){case"boolean":return"布尔";case"number":return"数字";default:return"字符串"}}function xw(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 fw({value:n,onChange:i,className:c,placeholder:d="添加额外参数..."}){const[h,f]=u.useState("list"),[x,j]=u.useState(()=>zu(n||{})),[p,w]=u.useState(()=>Object.keys(n||{}).length>0?JSON.stringify(n,null,2):""),[v,y]=u.useState(null);u.useEffect(()=>{const H=zu(n||{});j(H),w(Object.keys(n||{}).length>0?JSON.stringify(n,null,2):"")},[n]);const S=u.useMemo(()=>{const H=Mu(p);return H.valid&&H.parsed?{success:!0,data:H.parsed}:{success:!1,data:{}}},[p]),k=u.useCallback(H=>{const D=H;if(D==="json"&&h==="list"){const C=Au(x);w(Object.keys(C).length>0?JSON.stringify(C,null,2):""),y(null)}else if(D==="list"&&h==="json"){const C=Mu(p);C.valid&&C.parsed&&(j(zu(C.parsed)),y(null))}f(D)},[h,x,p]),O=u.useCallback(()=>{const H={id:crypto.randomUUID(),key:"",value:"",type:"string"},D=[...x,H];j(D)},[x]),Y=u.useCallback(H=>{const D=x.filter(C=>C.id!==H);j(D),i(Au(D))},[x,i]),L=u.useCallback((H,D,C)=>{const $=x.map(G=>{if(G.id!==H)return G;if(D==="type"){const T=C;let M;return T==="boolean"?M=G.value==="true"||G.value===!0:T==="number"?M=typeof G.value=="number"?G.value:parseFloat(String(G.value))||0:M=String(G.value),{...G,type:T,value:M}}else return D==="value"?{...G,value:mw(C,G.type)}:{...G,[D]:C}});j($),i(Au($))},[x,i]),R=u.useCallback(H=>{w(H);const D=Mu(H);D.valid&&D.parsed?(y(null),i(D.parsed)):y(D.error||"JSON 格式错误")},[i]);return e.jsxs("div",{className:X("space-y-3",c),children:[e.jsx(b,{className:"text-sm font-medium",children:"额外参数"}),e.jsxs(Ca,{value:h,onValueChange:k,className:"w-full",children:[e.jsxs(pa,{className:"h-8 p-0.5 bg-muted/60",children:[e.jsx(ns,{value:"list",className:"h-7 px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-sm",children:"键值对"}),e.jsx(ns,{value:"json",className:"h-7 px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-sm",children:"JSON"})]}),e.jsxs(Es,{value:"list",className:"mt-3 space-y-2",children:[x.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",{})]}),x.map(H=>e.jsxs("div",{className:"grid grid-cols-[1fr_1fr_90px_32px] gap-2 items-center",children:[e.jsx(ie,{value:H.key,onChange:D=>L(H.id,"key",D.target.value),placeholder:"key",className:"h-8 text-sm"}),H.type==="boolean"?e.jsxs("div",{className:"flex items-center h-8 px-3 border rounded-md bg-background",children:[e.jsx(Qe,{checked:H.value===!0,onCheckedChange:D=>L(H.id,"value",String(D))}),e.jsx("span",{className:"ml-2 text-sm text-muted-foreground",children:H.value?"true":"false"})]}):e.jsx(ie,{type:H.type==="number"?"number":"text",value:H.value,onChange:D=>L(H.id,"value",D.target.value),placeholder:"value",className:"h-8 text-sm",step:H.type==="number"?"any":void 0}),e.jsxs(Be,{value:H.type,onValueChange:D=>L(H.id,"type",D),children:[e.jsx(Le,{className:"h-8 text-xs",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"string",children:"字符串"}),e.jsx(te,{value:"number",children:"数字"}),e.jsx(te,{value:"boolean",children:"布尔"})]})]}),e.jsx(N,{type:"button",variant:"ghost",size:"icon",className:"h-8 w-8 text-muted-foreground hover:text-destructive",onClick:()=>Y(H.id),children:e.jsx(ts,{className:"h-4 w-4"})})]},H.id))]}),e.jsxs(N,{type:"button",variant:"outline",size:"sm",className:"w-full h-8",onClick:O,children:[e.jsx(ot,{className:"h-4 w-4 mr-1"}),"添加参数"]})]}),e.jsx(Es,{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(Sa,{className:"h-3 w-3"}),e.jsx("span",{className:"truncate max-w-[150px]",children:v})]}):p.trim()&&e.jsxs("div",{className:"flex items-center gap-1 text-xs text-green-600 dark:text-green-400",children:[e.jsx($t,{className:"h-3 w-3"}),e.jsx("span",{children:"有效"})]})]}),e.jsx(Bs,{value:p,onChange:H=>R(H.target.value),placeholder:`{ + "key": "value" +}`,className:X("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:S.success&&Object.keys(S.data).length>0?e.jsx("div",{className:"space-y-2",children:Object.entries(S.data).map(([H,D])=>{const C=Ug(D);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:H}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:X("font-mono",C==="boolean"&&(D?"text-green-600 dark:text-green-400":"text-red-600 dark:text-red-400"),C==="number"&&"text-blue-600 dark:text-blue-400",C==="string"&&"text-amber-600 dark:text-amber-400"),children:C==="string"?`"${D}"`:String(D)}),e.jsx($e,{variant:"secondary",className:X("h-5 text-[10px] px-1.5",xw(C)),children:hw(C)})]},H)})}):S.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:"实时预览解析结果"})]})]})})]})]})}const mp=new Map,pw=300*1e3;function gw(){const[n,i]=u.useState([]),[c,d]=u.useState([]),[h,f]=u.useState([]),[x,j]=u.useState([]),[p,w]=u.useState(null),[v,y]=u.useState(!0),[S,k]=u.useState(!1),[O,Y]=u.useState(!1),[L,R]=u.useState(!1),[H,D]=u.useState(!1),[C,$]=u.useState(!1),[G,T]=u.useState(!1),[M,ne]=u.useState(null),[fe,_e]=u.useState(null),[Se,je]=u.useState(!1),[ye,be]=u.useState(null),[A,K]=u.useState(""),[E,se]=u.useState(new Set),[_,me]=u.useState(!1),[re,le]=u.useState(1),[pe,Ne]=u.useState(20),[he,Q]=u.useState(""),[P,q]=u.useState([]),[W,Ce]=u.useState(!1),[Me,ce]=u.useState(null),[De,Fs]=u.useState(!1),[Qs,ue]=u.useState(null),[Ee,as]=u.useState({}),{toast:Ke}=Vs(),lt=ja(),{registerTour:Ot,startTour:bt,state:Pe,goToStep:U}=Wu(),Re=u.useRef(null),ze=u.useRef(null),Ye=u.useRef(!0);u.useEffect(()=>{Ot(il,Rg)},[Ot]),u.useEffect(()=>{if(Pe.activeTourId===il&&Pe.isRunning){const V=Lg[Pe.stepIndex];V&&!window.location.pathname.endsWith(V.replace("/config/",""))&<({to:V})}},[Pe.stepIndex,Pe.activeTourId,Pe.isRunning,lt]);const zs=u.useRef(Pe.stepIndex);u.useEffect(()=>{if(Pe.activeTourId===il&&Pe.isRunning){const V=zs.current,de=Pe.stepIndex;V>=12&&V<=17&&de<12&&T(!1),zs.current=de}},[Pe.stepIndex,Pe.activeTourId,Pe.isRunning]),u.useEffect(()=>{if(Pe.activeTourId!==il||!Pe.isRunning)return;const V=de=>{const qe=de.target,Je=Pe.stepIndex;Je===2&&qe.closest('[data-tour="add-provider-button"]')?setTimeout(()=>U(3),300):Je===9&&qe.closest('[data-tour="provider-cancel-button"]')?setTimeout(()=>U(10),300):Je===11&&qe.closest('[data-tour="add-model-button"]')?setTimeout(()=>U(12),300):Je===17&&qe.closest('[data-tour="model-cancel-button"]')?setTimeout(()=>U(18),300):Je===18&&qe.closest('[data-tour="tasks-tab-trigger"]')&&setTimeout(()=>U(19),300)};return document.addEventListener("click",V,!0),()=>document.removeEventListener("click",V,!0)},[Pe,U]);const We=()=>{bt(il)};u.useEffect(()=>{nt()},[]);const nt=async()=>{try{y(!0);const V=await ni(),de=V.models||[];i(de),j(de.map(Je=>Je.name));const qe=V.api_providers||[];d(qe.map(Je=>Je.name)),f(qe),w(V.model_task_config||null),R(!1),Ye.current=!1}catch(V){console.error("加载配置失败:",V)}finally{y(!1)}},vs=u.useCallback(V=>h.find(de=>de.name===V),[h]),ke=u.useCallback(async(V,de=!1)=>{const qe=vs(V);if(!qe?.base_url){q([]),ue(null),ce('提供商配置不完整,请先在"模型提供商配置"中配置');return}if(!qe.api_key){q([]),ue(null),ce('该提供商未配置 API Key,请先在"模型提供商配置"中填写');return}const Je=cw(qe.base_url);if(ue(Je),!Je?.modelFetcher){q([]),ce(null);return}const Ns=`${V}:${qe.base_url}`,ta=mp.get(Ns);if(!de&&ta&&Date.now()-ta.timestamp{G&&M?.api_provider&&ke(M.api_provider)},[G,M?.api_provider,ke]);const ve=async()=>{try{D(!0),lo().catch(()=>{}),$(!0)}catch(V){console.error("重启失败:",V),$(!1),Ke({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),D(!1)}},is=async()=>{try{k(!0),Re.current&&clearTimeout(Re.current),ze.current&&clearTimeout(ze.current);const V=await ni();V.models=n,V.model_task_config=p,await to(V),R(!1),Ke({title:"保存成功",description:"正在重启麦麦..."}),await ve()}catch(V){console.error("保存配置失败:",V),Ke({title:"保存失败",description:V.message,variant:"destructive"}),k(!1)}},_s=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},At=()=>{$(!1),D(!1),Ke({title:"重启超时",description:"服务未能在预期时间内恢复,请手动检查或刷新页面",variant:"destructive"})},Ps=u.useCallback(async V=>{if(!Ye.current)try{Y(!0),await qu("models",V),R(!1)}catch(de){console.error("自动保存模型列表失败:",de),R(!0)}finally{Y(!1)}},[]),Ys=u.useCallback(async V=>{if(!Ye.current)try{Y(!0),await qu("model_task_config",V),R(!1)}catch(de){console.error("自动保存任务配置失败:",de),R(!0)}finally{Y(!1)}},[]);u.useEffect(()=>{if(!Ye.current)return R(!0),Re.current&&clearTimeout(Re.current),Re.current=setTimeout(()=>{Ps(n)},2e3),()=>{Re.current&&clearTimeout(Re.current)}},[n,Ps]),u.useEffect(()=>{if(!(Ye.current||!p))return R(!0),ze.current&&clearTimeout(ze.current),ze.current=setTimeout(()=>{Ys(p)},2e3),()=>{ze.current&&clearTimeout(ze.current)}},[p,Ys]);const Et=async()=>{try{k(!0),Re.current&&clearTimeout(Re.current),ze.current&&clearTimeout(ze.current);const V=await ni();V.models=n,V.model_task_config=p,await to(V),R(!1),Ke({title:"保存成功",description:"模型配置已保存"}),await nt()}catch(V){console.error("保存配置失败:",V),Ke({title:"保存失败",description:V.message,variant:"destructive"})}finally{k(!1)}},Rt=(V,de)=>{as({}),ne(V||{model_identifier:"",name:"",api_provider:c[0]||"",price_in:0,price_out:0,temperature:null,max_tokens:null,force_stream_mode:!1,extra_params:{}}),_e(de),T(!0)},Ha=()=>{if(!M)return;const V={};if(M.name?.trim()||(V.name="请输入模型名称"),M.api_provider?.trim()||(V.api_provider="请选择 API 提供商"),M.model_identifier?.trim()||(V.model_identifier="请输入模型标识符"),Object.keys(V).length>0){as(V);return}as({});const de={...M,price_in:M.price_in??0,price_out:M.price_out??0};let qe,Je=null;if(fe!==null?(Je=n[fe].name,qe=[...n],qe[fe]=de):qe=[...n,de],i(qe),j(qe.map(Ns=>Ns.name)),Je&&Je!==de.name&&p){const Ns=ta=>ta.map(aa=>aa===Je?de.name:aa);w({...p,utils:{...p.utils,model_list:Ns(p.utils?.model_list||[])},utils_small:{...p.utils_small,model_list:Ns(p.utils_small?.model_list||[])},tool_use:{...p.tool_use,model_list:Ns(p.tool_use?.model_list||[])},replyer:{...p.replyer,model_list:Ns(p.replyer?.model_list||[])},planner:{...p.planner,model_list:Ns(p.planner?.model_list||[])},vlm:{...p.vlm,model_list:Ns(p.vlm?.model_list||[])},voice:{...p.voice,model_list:Ns(p.voice?.model_list||[])},embedding:{...p.embedding,model_list:Ns(p.embedding?.model_list||[])},lpmm_entity_extract:{...p.lpmm_entity_extract,model_list:Ns(p.lpmm_entity_extract?.model_list||[])},lpmm_rdf_build:{...p.lpmm_rdf_build,model_list:Ns(p.lpmm_rdf_build?.model_list||[])},lpmm_qa:{...p.lpmm_qa,model_list:Ns(p.lpmm_qa?.model_list||[])}})}T(!1),ne(null),_e(null)},Yt=V=>{if(!V&&M){const de={...M,price_in:M.price_in??0,price_out:M.price_out??0};ne(de)}T(V)},qa=V=>{be(V),je(!0)},Ta=()=>{if(ye!==null){const V=n.filter((de,qe)=>qe!==ye);i(V),j(V.map(de=>de.name)),Ke({title:"删除成功",description:"模型已从列表中移除"})}je(!1),be(null)},ee=V=>{const de=new Set(E);de.has(V)?de.delete(V):de.add(V),se(de)},we=()=>{if(E.size===Lt.length)se(new Set);else{const V=Lt.map((de,qe)=>n.findIndex(Je=>Je===Lt[qe]));se(new Set(V))}},Ve=()=>{if(E.size===0){Ke({title:"提示",description:"请先选择要删除的模型",variant:"default"});return}me(!0)},pt=()=>{const V=n.filter((de,qe)=>!E.has(qe));i(V),j(V.map(de=>de.name)),se(new Set),me(!1),Ke({title:"批量删除成功",description:`已删除 ${E.size} 个模型`})},Xt=(V,de,qe)=>{p&&w({...p,[V]:{...p[V],[de]:qe}})},Lt=n.filter(V=>{if(!A)return!0;const de=A.toLowerCase();return V.name.toLowerCase().includes(de)||V.model_identifier.toLowerCase().includes(de)||V.api_provider.toLowerCase().includes(de)}),hl=Math.ceil(Lt.length/pe),Vl=Lt.slice((re-1)*pe,re*pe),pn=()=>{const V=parseInt(he);V>=1&&V<=hl&&(le(V),Q(""))},gn=V=>p?[p.utils?.model_list||[],p.utils_small?.model_list||[],p.tool_use?.model_list||[],p.replyer?.model_list||[],p.planner?.model_list||[],p.vlm?.model_list||[],p.voice?.model_list||[],p.embedding?.model_list||[],p.lpmm_entity_extract?.model_list||[],p.lpmm_rdf_build?.model_list||[],p.lpmm_qa?.model_list||[]].some(qe=>qe.includes(V)):!1;return v?e.jsx(ss,{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(ss,{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(N,{onClick:Et,disabled:S||O||!L||H,size:"sm",variant:"outline",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(yr,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),S?"保存中...":O?"自动保存中...":L?"保存配置":"已保存"]}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsxs(N,{disabled:S||O||H,size:"sm",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(br,{className:"mr-2 h-4 w-4"}),H?"重启中...":L?"保存并重启":"重启麦麦"]})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认重启麦麦?"}),e.jsx(us,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:L?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:L?is:ve,children:L?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(cl,{children:[e.jsx(La,{className:"h-4 w-4"}),e.jsxs(ol,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(cl,{className:"hidden lg:flex border-primary/30 bg-primary/5 cursor-pointer hover:bg-primary/10 transition-colors",onClick:We,children:[e.jsx(Cb,{className:"h-4 w-4 text-primary"}),e.jsxs(ol,{className:"flex items-center justify-between",children:[e.jsxs("span",{children:[e.jsx("strong",{className:"text-primary",children:"新手引导:"}),"不知道如何配置模型?点击这里开始学习如何为麦麦的组件分配模型。"]}),e.jsx(N,{variant:"outline",size:"sm",className:"ml-4 shrink-0",children:"开始引导"})]})]}),e.jsxs(Ca,{defaultValue:"models",className:"w-full",children:[e.jsxs(pa,{className:"grid w-full max-w-full sm:max-w-md grid-cols-2",children:[e.jsx(ns,{value:"models",children:"添加模型"}),e.jsx(ns,{value:"tasks","data-tour":"tasks-tab-trigger",children:"为模型分配功能"})]}),e.jsxs(Es,{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:[E.size>0&&e.jsxs(N,{onClick:Ve,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(ts,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",E.size,")"]}),e.jsxs(N,{onClick:()=>Rt(null,null),size:"sm",variant:"outline",className:"w-full sm:w-auto","data-tour":"add-model-button",children:[e.jsx(ot,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索模型名称、标识符或提供商...",value:A,onChange:V=>K(V.target.value),className:"pl-9"})]}),A&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Lt.length," 个结果"]})]}),e.jsx("div",{className:"md:hidden space-y-3",children:Vl.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 rounded-lg border bg-card",children:A?"未找到匹配的模型":"暂无模型配置"}):Vl.map((V,de)=>{const qe=n.findIndex(Ns=>Ns===V),Je=gn(V.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:V.name}),e.jsx($e,{variant:Je?"default":"secondary",className:Je?"bg-green-600 hover:bg-green-700":"",children:Je?"已使用":"未使用"})]}),e.jsx("p",{className:"text-xs text-muted-foreground break-all",title:V.model_identifier,children:V.model_identifier})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>Rt(V,qe),children:[e.jsx(on,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>qa(qe),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ts,{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:V.api_provider})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"模型温度"}),e.jsx("p",{className:"font-medium",children:V.temperature!=null?V.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:["¥",V.price_in,"/M"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输出价格"}),e.jsxs("p",{className:"font-medium",children:["¥",V.price_out,"/M"]})]})]})]},de)})}),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(hn,{children:[e.jsx(xn,{children:e.jsxs(dt,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:E.size===Lt.length&&Lt.length>0,onCheckedChange:we})}),e.jsx(Ie,{className:"w-24",children:"使用状态"}),e.jsx(Ie,{children:"模型名称"}),e.jsx(Ie,{children:"模型标识符"}),e.jsx(Ie,{children:"提供商"}),e.jsx(Ie,{className:"text-center",children:"温度"}),e.jsx(Ie,{className:"text-right",children:"输入价格"}),e.jsx(Ie,{className:"text-right",children:"输出价格"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:Vl.length===0?e.jsx(dt,{children:e.jsx(Fe,{colSpan:9,className:"text-center text-muted-foreground py-8",children:A?"未找到匹配的模型":"暂无模型配置"})}):Vl.map((V,de)=>{const qe=n.findIndex(Ns=>Ns===V),Je=gn(V.name);return e.jsxs(dt,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:E.has(qe),onCheckedChange:()=>ee(qe)})}),e.jsx(Fe,{children:e.jsx($e,{variant:Je?"default":"secondary",className:Je?"bg-green-600 hover:bg-green-700":"",children:Je?"已使用":"未使用"})}),e.jsx(Fe,{className:"font-medium",children:V.name}),e.jsx(Fe,{className:"max-w-xs truncate",title:V.model_identifier,children:V.model_identifier}),e.jsx(Fe,{children:V.api_provider}),e.jsx(Fe,{className:"text-center",children:V.temperature!=null?V.temperature:e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsxs(Fe,{className:"text-right",children:["¥",V.price_in,"/M"]}),e.jsxs(Fe,{className:"text-right",children:["¥",V.price_out,"/M"]}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>Rt(V,qe),children:[e.jsx(on,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>qa(qe),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ts,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},de)})})]})})}),Lt.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(b,{htmlFor:"page-size-model",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Be,{value:pe.toString(),onValueChange:V=>{Ne(parseInt(V)),le(1),se(new Set)},children:[e.jsx(Le,{id:"page-size-model",className:"w-20",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"10",children:"10"}),e.jsx(te,{value:"20",children:"20"}),e.jsx(te,{value:"50",children:"50"}),e.jsx(te,{value:"100",children:"100"})]})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["显示 ",(re-1)*pe+1," 到"," ",Math.min(re*pe,Lt.length)," 条,共 ",Lt.length," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>le(1),disabled:re===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>le(V=>Math.max(1,V-1)),disabled:re===1,children:[e.jsx(Hl,{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:he,onChange:V=>Q(V.target.value),onKeyDown:V=>V.key==="Enter"&&pn(),placeholder:re.toString(),className:"w-16 h-8 text-center",min:1,max:hl}),e.jsx(N,{variant:"outline",size:"sm",onClick:pn,disabled:!he,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>le(V=>V+1),disabled:re>=hl,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>le(hl),disabled:re>=hl,className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]}),e.jsxs(Es,{value:"tasks",className:"space-y-6 mt-0",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"为不同的任务配置使用的模型和参数"}),p&&e.jsxs("div",{className:"grid gap-4 sm:gap-6",children:[e.jsx(ya,{title:"组件模型 (utils)",description:"用于表情包、取名、关系、情绪变化等组件",taskConfig:p.utils,modelNames:x,onChange:(V,de)=>Xt("utils",V,de),dataTour:"task-model-select"}),e.jsx(ya,{title:"组件小模型 (utils_small)",description:"消耗量较大的组件,建议使用速度较快的小模型",taskConfig:p.utils_small,modelNames:x,onChange:(V,de)=>Xt("utils_small",V,de)}),e.jsx(ya,{title:"工具调用模型 (tool_use)",description:"需要使用支持工具调用的模型",taskConfig:p.tool_use,modelNames:x,onChange:(V,de)=>Xt("tool_use",V,de)}),e.jsx(ya,{title:"首要回复模型 (replyer)",description:"用于表达器和表达方式学习",taskConfig:p.replyer,modelNames:x,onChange:(V,de)=>Xt("replyer",V,de)}),e.jsx(ya,{title:"决策模型 (planner)",description:"负责决定麦麦该什么时候回复",taskConfig:p.planner,modelNames:x,onChange:(V,de)=>Xt("planner",V,de)}),e.jsx(ya,{title:"图像识别模型 (vlm)",description:"视觉语言模型",taskConfig:p.vlm,modelNames:x,onChange:(V,de)=>Xt("vlm",V,de),hideTemperature:!0}),e.jsx(ya,{title:"语音识别模型 (voice)",description:"语音转文字",taskConfig:p.voice,modelNames:x,onChange:(V,de)=>Xt("voice",V,de),hideTemperature:!0,hideMaxTokens:!0}),e.jsx(ya,{title:"嵌入模型 (embedding)",description:"用于向量化",taskConfig:p.embedding,modelNames:x,onChange:(V,de)=>Xt("embedding",V,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(ya,{title:"实体提取模型 (lpmm_entity_extract)",description:"从文本中提取实体",taskConfig:p.lpmm_entity_extract,modelNames:x,onChange:(V,de)=>Xt("lpmm_entity_extract",V,de)}),e.jsx(ya,{title:"RDF 构建模型 (lpmm_rdf_build)",description:"构建知识图谱",taskConfig:p.lpmm_rdf_build,modelNames:x,onChange:(V,de)=>Xt("lpmm_rdf_build",V,de)}),e.jsx(ya,{title:"问答模型 (lpmm_qa)",description:"知识库问答",taskConfig:p.lpmm_qa,modelNames:x,onChange:(V,de)=>Xt("lpmm_qa",V,de)})]})]})]})]}),e.jsx($s,{open:G,onOpenChange:Yt,children:e.jsxs(Hs,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"model-dialog",preventOutsideClose:Pe.isRunning,children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:fe!==null?"编辑模型":"添加模型"}),e.jsx(Is,{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(b,{htmlFor:"model_name",className:Ee.name?"text-destructive":"",children:"模型名称 *"}),e.jsx(ie,{id:"model_name",value:M?.name||"",onChange:V=>{ne(de=>de?{...de,name:V.target.value}:null),Ee.name&&as(de=>({...de,name:void 0}))},placeholder:"例如: qwen3-30b",className:Ee.name?"border-destructive focus-visible:ring-destructive":""}),Ee.name?e.jsx("p",{className:"text-xs text-destructive",children:Ee.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(b,{htmlFor:"api_provider",className:Ee.api_provider?"text-destructive":"",children:"API 提供商 *"}),e.jsxs(Be,{value:M?.api_provider||"",onValueChange:V=>{ne(de=>de?{...de,api_provider:V}:null),q([]),ce(null),Ee.api_provider&&as(de=>({...de,api_provider:void 0}))},children:[e.jsx(Le,{id:"api_provider",className:Ee.api_provider?"border-destructive focus-visible:ring-destructive":"",children:e.jsx(He,{placeholder:"选择提供商"})}),e.jsx(Ue,{children:c.map(V=>e.jsx(te,{value:V,children:V},V))})]}),Ee.api_provider&&e.jsx("p",{className:"text-xs text-destructive",children:Ee.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(b,{htmlFor:"model_identifier",className:Ee.model_identifier?"text-destructive":"",children:"模型标识符 *"}),Qs?.modelFetcher&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx($e,{variant:"secondary",className:"text-xs",children:Qs.display_name}),e.jsx(N,{variant:"ghost",size:"sm",className:"h-6 px-2",onClick:()=>M?.api_provider&&ke(M.api_provider,!0),disabled:W,children:W?e.jsx(kt,{className:"h-3 w-3 animate-spin"}):e.jsx(Ct,{className:"h-3 w-3"})})]})]}),Qs?.modelFetcher?e.jsxs(Ua,{open:De,onOpenChange:Fs,children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",role:"combobox","aria-expanded":De,className:"w-full justify-between font-normal",disabled:W||!!Me,children:[W?e.jsxs("span",{className:"flex items-center gap-2 text-muted-foreground",children:[e.jsx(kt,{className:"h-4 w-4 animate-spin"}),"正在获取模型列表..."]}):Me?e.jsx("span",{className:"text-muted-foreground text-sm",children:"点击下方输入框手动填写"}):M?.model_identifier?e.jsx("span",{className:"truncate",children:M.model_identifier}):e.jsx("span",{className:"text-muted-foreground",children:"搜索或选择模型..."}),e.jsx(Yu,{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(no,{children:[e.jsx(io,{placeholder:"搜索模型..."}),e.jsx(ss,{className:"h-[300px]",children:e.jsxs(ro,{className:"max-h-none overflow-visible",children:[e.jsx(co,{children:Me?e.jsxs("div",{className:"py-4 px-2 text-center space-y-2",children:[e.jsx("p",{className:"text-sm text-destructive",children:Me}),!Me.includes("API Key")&&e.jsx(N,{variant:"link",size:"sm",onClick:()=>M?.api_provider&&ke(M.api_provider,!0),children:"重试"})]}):"未找到匹配的模型"}),e.jsx(vr,{heading:"可用模型",children:P.map(V=>e.jsxs(Nr,{value:V.id,onSelect:()=>{ne(de=>de?{...de,model_identifier:V.id}:null),Fs(!1)},children:[e.jsx($t,{className:`mr-2 h-4 w-4 ${M?.model_identifier===V.id?"opacity-100":"opacity-0"}`}),e.jsxs("div",{className:"flex flex-col",children:[e.jsx("span",{children:V.id}),V.name!==V.id&&e.jsx("span",{className:"text-xs text-muted-foreground",children:V.name})]})]},V.id))}),e.jsx(vr,{heading:"手动输入",children:e.jsxs(Nr,{value:"__manual_input__",onSelect:()=>{Fs(!1)},children:[e.jsx(on,{className:"mr-2 h-4 w-4"}),"手动输入模型标识符..."]})})]})})]})})]}):e.jsx(ie,{id:"model_identifier",value:M?.model_identifier||"",onChange:V=>{ne(de=>de?{...de,model_identifier:V.target.value}:null),Ee.model_identifier&&as(de=>({...de,model_identifier:void 0}))},placeholder:"Qwen/Qwen3-30B-A3B-Instruct-2507",className:Ee.model_identifier?"border-destructive focus-visible:ring-destructive":""}),Ee.model_identifier&&e.jsx("p",{className:"text-xs text-destructive",children:Ee.model_identifier}),Me&&Qs?.modelFetcher&&!Ee.model_identifier&&e.jsxs(cl,{variant:"destructive",className:"mt-2 py-2",children:[e.jsx(La,{className:"h-4 w-4"}),e.jsx(ol,{className:"text-xs",children:Me})]}),Qs?.modelFetcher&&e.jsx(ie,{value:M?.model_identifier||"",onChange:V=>{ne(de=>de?{...de,model_identifier:V.target.value}:null),Ee.model_identifier&&as(de=>({...de,model_identifier:void 0}))},placeholder:"或手动输入模型标识符",className:`mt-2 ${Ee.model_identifier?"border-destructive focus-visible:ring-destructive":""}`}),!Ee.model_identifier&&e.jsx("p",{className:"text-xs text-muted-foreground",children:Me?'请手动输入模型标识符,或前往"模型提供商配置"检查 API Key':Qs?.modelFetcher?`已识别为 ${Qs.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(b,{htmlFor:"price_in",children:"输入价格 (¥/M token)"}),e.jsx(ie,{id:"price_in",type:"number",step:"0.1",min:"0",value:M?.price_in??"",onChange:V=>{const de=V.target.value===""?null:parseFloat(V.target.value);ne(qe=>qe?{...qe,price_in:de}:null)},placeholder:"默认: 0"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{htmlFor:"price_out",children:"输出价格 (¥/M token)"}),e.jsx(ie,{id:"price_out",type:"number",step:"0.1",min:"0",value:M?.price_out??"",onChange:V=>{const de=V.target.value===""?null:parseFloat(V.target.value);ne(qe=>qe?{...qe,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(b,{htmlFor:"enable_model_temperature",className:"cursor-pointer",children:"自定义模型温度"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后将覆盖「为模型分配功能」中的任务温度配置"})]}),e.jsx(Qe,{id:"enable_model_temperature",checked:M?.temperature!=null,onCheckedChange:V=>{ne(V?de=>de?{...de,temperature:.5}:null:de=>de?{...de,temperature:null}:null)}})]}),M?.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(b,{className:"text-sm",children:"温度值"}),e.jsx("span",{className:"text-sm font-medium tabular-nums",children:M.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(wa,{value:[M.temperature],onValueChange:V=>ne(de=>de?{...de,temperature:V[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(b,{htmlFor:"enable_model_max_tokens",className:"cursor-pointer",children:"自定义最大 Token"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后将覆盖「为模型分配功能」中的任务最大 Token 配置"})]}),e.jsx(Qe,{id:"enable_model_max_tokens",checked:M?.max_tokens!=null,onCheckedChange:V=>{ne(V?de=>de?{...de,max_tokens:2048}:null:de=>de?{...de,max_tokens:null}:null)}})]}),M?.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(b,{className:"text-sm",children:"最大 Token 数"}),e.jsx(ie,{type:"number",min:"1",max:"128000",value:M.max_tokens,onChange:V=>{const de=parseInt(V.target.value);!isNaN(de)&&de>=1&&ne(qe=>qe?{...qe,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(Qe,{id:"force_stream_mode",checked:M?.force_stream_mode||!1,onCheckedChange:V=>ne(de=>de?{...de,force_stream_mode:V}:null)}),e.jsx(b,{htmlFor:"force_stream_mode",className:"cursor-pointer",children:"强制流式输出模式"})]}),e.jsx(fw,{value:M?.extra_params||{},onChange:V=>ne(de=>de?{...de,extra_params:V}:null),placeholder:"添加额外参数(如 enable_thinking、top_p 等)..."})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>T(!1),"data-tour":"model-cancel-button",children:"取消"}),e.jsx(N,{onClick:Ha,"data-tour":"model-save-button",children:"保存"})]})]})}),e.jsx(ps,{open:Se,onOpenChange:je,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除模型 "',ye!==null?n[ye]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:Ta,children:"删除"})]})]})}),e.jsx(ps,{open:_,onOpenChange:me,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认批量删除"}),e.jsxs(us,{children:["确定要删除选中的 ",E.size," 个模型吗? 此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:pt,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),C&&e.jsx(Pu,{onRestartComplete:_s,onRestartFailed:At})]})})}function ya({title:n,description:i,taskConfig:c,modelNames:d,onChange:h,hideTemperature:f=!1,hideMaxTokens:x=!1,dataTour:j}){const p=w=>{h("model_list",w)};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:n}),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":j,children:[e.jsx(b,{children:"模型列表"}),e.jsx(uw,{options:d.map(w=>({label:w,value:w})),selected:c.model_list||[],onChange:p,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(b,{children:"温度"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"1",value:c.temperature??.3,onChange:w=>{const v=parseFloat(w.target.value);!isNaN(v)&&v>=0&&v<=1&&h("temperature",v)},className:"w-20 h-8 text-sm"})]}),e.jsx(wa,{value:[c.temperature??.3],onValueChange:w=>h("temperature",w[0]),min:0,max:1,step:.1,className:"w-full"})]}),!x&&e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"最大 Token"}),e.jsx(ie,{type:"number",step:"1",min:"1",value:c.max_tokens??1024,onChange:w=>h("max_tokens",parseInt(w.target.value))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(b,{children:"慢请求阈值 (秒)"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"超时警告"})]}),e.jsx(ie,{type:"number",step:"1",min:"1",value:c.slow_threshold??15,onChange:w=>{const v=parseInt(w.target.value);!isNaN(v)&&v>=1&&h("slow_threshold",v)},placeholder:"15"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"模型响应时间超过此阈值将输出警告日志"})]})]})]})}const oo="/api/webui/config";async function jw(){const i=await(await Te(`${oo}/adapter-config/path`)).json();return!i.success||!i.path?null:{path:i.path,lastModified:i.lastModified}}async function hp(n){const c=await(await Te(`${oo}/adapter-config/path`,{method:"POST",headers:Ls(),body:JSON.stringify({path:n})})).json();if(!c.success)throw new Error(c.message||"保存路径失败")}async function xp(n){const c=await(await Te(`${oo}/adapter-config?path=${encodeURIComponent(n)}`)).json();if(!c.success)throw new Error("读取配置文件失败");return c.content}async function fp(n,i){const d=await(await Te(`${oo}/adapter-config`,{method:"POST",headers:Ls(),body:JSON.stringify({path:n,content:i})})).json();if(!d.success)throw new Error(d.message||"保存配置失败")}const sa={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"}},Du={oneclick:{name:"一键包",description:"使用一键包部署的适配器配置",path:"../MaiBot-Napcat-Adapter/config.toml",icon:dn},docker:{name:"Docker",description:"Docker Compose 部署的适配器配置",path:"/MaiMBot/adapters-config/config.toml",icon:kb}};function vw(){const[n,i]=u.useState("upload"),[c,d]=u.useState(null),[h,f]=u.useState(""),[x,j]=u.useState(""),[p,w]=u.useState("oneclick"),[v,y]=u.useState(""),[S,k]=u.useState(!1),[O,Y]=u.useState(!1),[L,R]=u.useState(!1),[H,D]=u.useState(!1),[C,$]=u.useState(null),G=u.useRef(null),{toast:T}=Vs(),M=u.useRef(null),ne=Q=>{if(!Q.trim())return{valid:!1,error:"路径不能为空"};if(!Q.toLowerCase().endsWith(".toml"))return{valid:!1,error:"文件必须是 .toml 格式"};const P=/^([a-zA-Z]:\\|\\\\[^\\]+\\[^\\]+\\).+\.toml$/i,q=/^(\/|~\/).+\.toml$/i,W=/^(\.{1,2}[\\/]|[^:\\/]).+\.toml$/i,Ce=P.test(Q),Me=q.test(Q),ce=W.test(Q);return!Ce&&!Me&&!ce?{valid:!1,error:"路径格式错误"}:/[<>"|?*\x00-\x1F]/.test(Q)?{valid:!1,error:"路径包含非法字符"}:{valid:!0,error:""}},fe=Q=>{if(j(Q),Q.trim()){const P=ne(Q);y(P.error)}else y("")},_e=u.useCallback(async Q=>{const P=Du[Q];Y(!0);try{const q=await xp(P.path),W=re(q);d(W),w(Q),j(P.path),await hp(P.path),T({title:"加载成功",description:`已从${P.name}预设加载配置`})}catch(q){console.error("加载预设配置失败:",q),T({title:"加载失败",description:q instanceof Error?q.message:"无法读取预设配置文件",variant:"destructive"})}finally{Y(!1)}},[T]),Se=u.useCallback(async Q=>{const P=ne(Q);if(!P.valid){y(P.error),T({title:"路径无效",description:P.error,variant:"destructive"});return}y(""),Y(!0);try{const q=await xp(Q),W=re(q);d(W),j(Q),await hp(Q),T({title:"加载成功",description:"已从配置文件加载"})}catch(q){console.error("加载配置失败:",q),T({title:"加载失败",description:q instanceof Error?q.message:"无法读取配置文件",variant:"destructive"})}finally{Y(!1)}},[T]);u.useEffect(()=>{(async()=>{try{const P=await jw();if(P&&P.path){j(P.path);const q=Object.entries(Du).find(([,W])=>W.path===P.path);q?(i("preset"),w(q[0]),await _e(q[0])):(i("path"),await Se(P.path))}}catch(P){console.error("加载保存的路径失败:",P)}})()},[Se,_e]);const je=u.useCallback(Q=>{n!=="path"&&n!=="preset"||!x||(M.current&&clearTimeout(M.current),M.current=setTimeout(async()=>{k(!0);try{const P=le(Q);await fp(x,P),T({title:"自动保存成功",description:"配置已保存到文件"})}catch(P){console.error("自动保存失败:",P),T({title:"自动保存失败",description:P instanceof Error?P.message:"保存配置失败",variant:"destructive"})}finally{k(!1)}},1e3))},[n,x,T]),ye=async()=>{if(!c||!x)return;const Q=ne(x);if(!Q.valid){T({title:"保存失败",description:Q.error,variant:"destructive"});return}k(!0);try{const P=le(c);await fp(x,P),T({title:"保存成功",description:"配置已保存到文件"})}catch(P){console.error("保存失败:",P),T({title:"保存失败",description:P instanceof Error?P.message:"保存配置失败",variant:"destructive"})}finally{k(!1)}},be=async()=>{x&&await Se(x)},A=Q=>{if(Q!==n){if(c){$(Q),R(!0);return}K(Q)}},K=Q=>{d(null),f(""),y(""),i(Q),Q==="preset"&&_e("oneclick"),T({title:"已切换模式",description:{upload:"现在可以上传配置文件",path:"现在可以指定配置文件路径",preset:"现在可以使用预设配置"}[Q]})},E=()=>{C&&(K(C),$(null)),R(!1)},se=()=>{if(c){D(!0);return}_()},_=()=>{j(""),d(null),y(""),T({title:"已清空",description:"路径和配置已清空"})},me=()=>{_(),D(!1)},re=Q=>{const P=JSON.parse(JSON.stringify(sa)),q=Q.split(` +`);let W="";for(const Ce of q){const Me=Ce.trim();if(!Me||Me.startsWith("#"))continue;const ce=Me.match(/^\[(\w+)\]/);if(ce){W=ce[1];continue}const De=Me.match(/^(\w+)\s*=\s*(.+)$/);if(De&&W){const[,Fs,Qs]=De;let ue=Qs.trim();const Ee=ue.match(/^("[^"]*")/);if(Ee)ue=Ee[1];else{const Ke=ue.indexOf("#");Ke!==-1&&(ue=ue.substring(0,Ke).trim())}let as;if(ue==="true")as=!0;else if(ue==="false")as=!1;else if(ue.startsWith("[")&&ue.endsWith("]")){const Ke=ue.slice(1,-1).trim();if(Ke){const lt=Ke.split(",").map(bt=>{const Pe=bt.trim();return isNaN(Number(Pe))?Pe.replace(/"/g,""):Number(Pe)}),Ot=typeof lt[0];as=lt.every(bt=>typeof bt===Ot)?lt:lt.filter(bt=>typeof bt=="number")}else as=[]}else ue.startsWith('"')&&ue.endsWith('"')?as=ue.slice(1,-1):isNaN(Number(ue))?as=ue.replace(/"/g,""):as=Number(ue);if(W in P){const Ke=P[W];Ke[Fs]=as}}}return P},le=Q=>{const P=[],q=(W,Ce)=>W===""||W===null||W===void 0?Ce:W;return P.push("[inner]"),P.push(`version = "${q(Q.inner.version,sa.inner.version)}" # 版本号`),P.push("# 请勿修改版本号,除非你知道自己在做什么"),P.push(""),P.push("[nickname] # 现在没用"),P.push(`nickname = "${q(Q.nickname.nickname,sa.nickname.nickname)}"`),P.push(""),P.push("[napcat_server] # Napcat连接的ws服务设置"),P.push(`host = "${q(Q.napcat_server.host,sa.napcat_server.host)}" # Napcat设定的主机地址`),P.push(`port = ${q(Q.napcat_server.port||0,sa.napcat_server.port)} # Napcat设定的端口`),P.push(`token = "${q(Q.napcat_server.token,sa.napcat_server.token)}" # Napcat设定的访问令牌,若无则留空`),P.push(`heartbeat_interval = ${q(Q.napcat_server.heartbeat_interval||0,sa.napcat_server.heartbeat_interval)} # 与Napcat设置的心跳相同(按秒计)`),P.push(""),P.push("[maibot_server] # 连接麦麦的ws服务设置"),P.push(`host = "${q(Q.maibot_server.host,sa.maibot_server.host)}" # 麦麦在.env文件中设置的主机地址,即HOST字段`),P.push(`port = ${q(Q.maibot_server.port||0,sa.maibot_server.port)} # 麦麦在.env文件中设置的端口,即PORT字段`),P.push(""),P.push("[chat] # 黑白名单功能"),P.push(`group_list_type = "${q(Q.chat.group_list_type,sa.chat.group_list_type)}" # 群组名单类型,可选为:whitelist, blacklist`),P.push(`group_list = [${Q.chat.group_list.join(", ")}] # 群组名单`),P.push("# 当group_list_type为whitelist时,只有群组名单中的群组可以聊天"),P.push("# 当group_list_type为blacklist时,群组名单中的任何群组无法聊天"),P.push(`private_list_type = "${q(Q.chat.private_list_type,sa.chat.private_list_type)}" # 私聊名单类型,可选为:whitelist, blacklist`),P.push(`private_list = [${Q.chat.private_list.join(", ")}] # 私聊名单`),P.push("# 当private_list_type为whitelist时,只有私聊名单中的用户可以聊天"),P.push("# 当private_list_type为blacklist时,私聊名单中的任何用户无法聊天"),P.push(`ban_user_id = [${Q.chat.ban_user_id.join(", ")}] # 全局禁止名单(全局禁止名单中的用户无法进行任何聊天)`),P.push(`ban_qq_bot = ${Q.chat.ban_qq_bot} # 是否屏蔽QQ官方机器人`),P.push(`enable_poke = ${Q.chat.enable_poke} # 是否启用戳一戳功能`),P.push(""),P.push("[voice] # 发送语音设置"),P.push(`use_tts = ${Q.voice.use_tts} # 是否使用tts语音(请确保你配置了tts并有对应的adapter)`),P.push(""),P.push("[debug]"),P.push(`level = "${q(Q.debug.level,sa.debug.level)}" # 日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)`),P.join(` +`)},pe=Q=>{const P=Q.target.files?.[0];if(!P)return;const q=new FileReader;q.onload=W=>{try{const Ce=W.target?.result,Me=re(Ce);d(Me),f(P.name),T({title:"上传成功",description:`已加载配置文件:${P.name}`})}catch(Ce){console.error("解析配置文件失败:",Ce),T({title:"解析失败",description:"配置文件格式错误,请检查文件内容",variant:"destructive"})}},q.readAsText(P)},Ne=()=>{if(!c)return;const Q=le(c),P=new Blob([Q],{type:"text/plain;charset=utf-8"}),q=URL.createObjectURL(P),W=document.createElement("a");W.href=q,W.download=h||"config.toml",document.body.appendChild(W),W.click(),document.body.removeChild(W),URL.revokeObjectURL(q),T({title:"下载成功",description:"配置文件已下载,请手动覆盖并重启适配器"})},he=()=>{d(JSON.parse(JSON.stringify(sa))),f("config.toml"),T({title:"已加载默认配置",description:"可以开始编辑配置"})};return e.jsx(ss,{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(Sa,{className:"h-4 w-4 mt-0.5 flex-shrink-0"}),e.jsx("p",{className:"text-sm",children:"适配器配置保存之后使用 WebUI 的重启功能适配器并不会重启,需要手动重启适配器。"})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"工作模式"}),e.jsx(ct,{children:"选择配置文件的管理方式"})]}),e.jsxs(Ts,{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:()=>A("preset"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(dn,{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:()=>A("upload"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(fr,{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:()=>A("path"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(Tb,{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(b,{className:"text-sm md:text-base",children:"选择部署方式"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:Object.entries(Du).map(([Q,P])=>{const q=P.icon,W=p===Q;return e.jsx("div",{className:`border-2 rounded-lg p-3 cursor-pointer transition-all ${W?"border-primary bg-primary/5":"border-muted hover:border-primary/50"}`,onClick:()=>{w(Q),_e(Q)},children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(q,{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:P.name}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:P.description}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 font-mono break-all",children:P.path})]})]})},Q)})})]}),n==="path"&&e.jsxs("div",{className:"space-y-3 pt-2 border-t",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{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:x,onChange:Q=>fe(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(N,{onClick:()=>Se(x),disabled:O||!x||!!v,className:"w-full sm:w-auto",children:O?e.jsxs(e.Fragment,{children:[e.jsx(Ct,{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(cl,{children:[e.jsx(La,{className:"h-4 w-4"}),e.jsx(ol,{children:n==="preset"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"预设模式:"}),"选择预设的部署方式,配置会自动加载,修改后 1 秒自动保存",S&&" (正在保存...)"]}):n==="upload"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"上传文件模式:"}),"上传配置文件 → 在线编辑 → 下载文件 → 手动覆盖并重启适配器"]}):e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"指定路径模式:"}),"指定配置文件路径后,配置会自动加载,修改后 1 秒自动保存",S&&" (正在保存...)"]})})]}),n==="upload"&&!c&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 w-full",children:[e.jsx("input",{ref:G,type:"file",accept:".toml",className:"hidden",onChange:pe}),e.jsxs(N,{onClick:()=>G.current?.click(),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(fr,{className:"mr-2 h-4 w-4"}),"上传配置"]}),e.jsxs(N,{onClick:he,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(Ra,{className:"mr-2 h-4 w-4"}),"使用默认配置"]})]}),n==="upload"&&c&&e.jsx("div",{className:"flex gap-2",children:e.jsxs(N,{onClick:Ne,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(rl,{className:"mr-2 h-4 w-4"}),"下载配置"]})}),(n==="preset"||n==="path")&&c&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs(N,{onClick:ye,size:"sm",disabled:S||!!v,className:"w-full sm:w-auto",children:[e.jsx(yr,{className:"mr-2 h-4 w-4"}),S?"保存中...":"立即保存"]}),e.jsxs(N,{onClick:be,size:"sm",variant:"outline",disabled:O,className:"w-full sm:w-auto",children:[e.jsx(Ct,{className:`mr-2 h-4 w-4 ${O?"animate-spin":""}`}),"刷新"]}),n==="path"&&e.jsxs(N,{onClick:se,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(ts,{className:"mr-2 h-4 w-4"}),"清空路径"]})]}),c?e.jsxs(Ca,{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(pa,{className:"inline-flex w-auto min-w-full sm:grid sm:w-full sm:grid-cols-5",children:[e.jsxs(ns,{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(ns,{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(ns,{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(ns,{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(ns,{value:"debug",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:"调试"})]})}),e.jsx(Es,{value:"napcat",className:"space-y-4",children:e.jsx(Nw,{config:c,onChange:Q=>{d(Q),je(Q)}})}),e.jsx(Es,{value:"maibot",className:"space-y-4",children:e.jsx(bw,{config:c,onChange:Q=>{d(Q),je(Q)}})}),e.jsx(Es,{value:"chat",className:"space-y-4",children:e.jsx(yw,{config:c,onChange:Q=>{d(Q),je(Q)}})}),e.jsx(Es,{value:"voice",className:"space-y-4",children:e.jsx(ww,{config:c,onChange:Q=>{d(Q),je(Q)}})}),e.jsx(Es,{value:"debug",className:"space-y-4",children:e.jsx(_w,{config:c,onChange:Q=>{d(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(Ra,{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(ps,{open:L,onOpenChange:R,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认切换模式"}),e.jsxs(us,{children:["切换模式将清空当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-destructive font-medium",children:"请确保已保存重要配置"})]})]}),e.jsxs(os,{children:[e.jsx(hs,{onClick:()=>{R(!1),$(null)},children:"取消"}),e.jsx(ms,{onClick:E,children:"确认切换"})]})]})}),e.jsx(ps,{open:H,onOpenChange:D,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认清空路径"}),e.jsxs(us,{children:["清空路径将清除当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-muted-foreground text-sm",children:"此操作不会删除配置文件,只是清除界面中的配置"})]})]}),e.jsxs(os,{children:[e.jsx(hs,{onClick:()=>D(!1),children:"取消"}),e.jsx(ms,{onClick:me,className:"bg-destructive hover:bg-destructive/90",children:"确认清空"})]})]})})]})})}function Nw({config:n,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(b,{htmlFor:"napcat-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(ie,{id:"napcat-host",value:n.napcat_server.host,onChange:c=>i({...n,napcat_server:{...n.napcat_server,host:c.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(b,{htmlFor:"napcat-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(ie,{id:"napcat-port",type:"number",value:n.napcat_server.port||"",onChange:c=>i({...n,napcat_server:{...n.napcat_server,port:c.target.value?parseInt(c.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(b,{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:c=>i({...n,napcat_server:{...n.napcat_server,token:c.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(b,{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:c=>i({...n,napcat_server:{...n.napcat_server,heartbeat_interval:c.target.value?parseInt(c.target.value):0}}),placeholder:"30",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"与 Napcat 设置的心跳间隔保持一致(留空使用默认值 30)"})]})]})]})})}function bw({config:n,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(b,{htmlFor:"maibot-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(ie,{id:"maibot-host",value:n.maibot_server.host,onChange:c=>i({...n,maibot_server:{...n.maibot_server,host:c.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(b,{htmlFor:"maibot-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(ie,{id:"maibot-port",type:"number",value:n.maibot_server.port||"",onChange:c=>i({...n,maibot_server:{...n.maibot_server,port:c.target.value?parseInt(c.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 yw({config:n,onChange:i}){const c=f=>{const x={...n};f==="group"?x.chat.group_list=[...x.chat.group_list,0]:f==="private"?x.chat.private_list=[...x.chat.private_list,0]:x.chat.ban_user_id=[...x.chat.ban_user_id,0],i(x)},d=(f,x)=>{const j={...n};f==="group"?j.chat.group_list=j.chat.group_list.filter((p,w)=>w!==x):f==="private"?j.chat.private_list=j.chat.private_list.filter((p,w)=>w!==x):j.chat.ban_user_id=j.chat.ban_user_id.filter((p,w)=>w!==x),i(j)},h=(f,x,j)=>{const p={...n};f==="group"?p.chat.group_list[x]=j:f==="private"?p.chat.private_list[x]=j:p.chat.ban_user_id[x]=j,i(p)};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(b,{className:"text-sm md:text-base",children:"群组名单类型"}),e.jsxs(Be,{value:n.chat.group_list_type,onValueChange:f=>i({...n,chat:{...n.chat,group_list_type:f}}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"whitelist",children:"白名单(仅名单内可聊天)"}),e.jsx(te,{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(b,{className:"text-sm md:text-base",children:"群组列表"}),e.jsxs(N,{onClick:()=>c("group"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Ra,{className:"mr-1 h-4 w-4"}),"添加群号"]})]}),n.chat.group_list.map((f,x)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:f,onChange:j=>h("group",x,parseInt(j.target.value)||0),placeholder:"输入群号",className:"text-sm md:text-base"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除群号 ",f," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d("group",x),children:"删除"})]})]})]})]},x)),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(b,{className:"text-sm md:text-base",children:"私聊名单类型"}),e.jsxs(Be,{value:n.chat.private_list_type,onValueChange:f=>i({...n,chat:{...n.chat,private_list_type:f}}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"whitelist",children:"白名单(仅名单内可聊天)"}),e.jsx(te,{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(b,{className:"text-sm md:text-base",children:"私聊列表"}),e.jsxs(N,{onClick:()=>c("private"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Ra,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),n.chat.private_list.map((f,x)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:f,onChange:j=>h("private",x,parseInt(j.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要删除用户 ",f," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d("private",x),children:"删除"})]})]})]})]},x)),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(b,{className:"text-sm md:text-base",children:"全局禁止名单"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"名单中的用户无法进行任何聊天"})]}),e.jsxs(N,{onClick:()=>c("ban"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Ra,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),n.chat.ban_user_id.map((f,x)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:f,onChange:j=>h("ban",x,parseInt(j.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(ps,{children:[e.jsx(tt,{asChild:!0,children:e.jsx(N,{size:"icon",variant:"outline",children:e.jsx(ts,{className:"h-4 w-4"})})}),e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:["确定要从全局禁止名单中删除用户 ",f," 吗?此操作无法撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>d("ban",x),children:"删除"})]})]})]})]},x)),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(b,{className:"text-sm md:text-base",children:"屏蔽QQ官方机器人"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否屏蔽来自QQ官方机器人的消息"})]}),e.jsx(Qe,{checked:n.chat.ban_qq_bot,onCheckedChange:f=>i({...n,chat:{...n.chat,ban_qq_bot:f}})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(b,{className:"text-sm md:text-base",children:"启用戳一戳功能"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否响应戳一戳消息"})]}),e.jsx(Qe,{checked:n.chat.enable_poke,onCheckedChange:f=>i({...n,chat:{...n.chat,enable_poke:f}})})]})]})]})})}function ww({config:n,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(b,{className:"text-sm md:text-base",children:"使用 TTS 语音"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"请确保已配置 TTS 并有对应的适配器"})]}),e.jsx(Qe,{checked:n.voice.use_tts,onCheckedChange:c=>i({...n,voice:{use_tts:c}})})]})]})})}function _w({config:n,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(b,{className:"text-sm md:text-base",children:"日志等级"}),e.jsxs(Be,{value:n.debug.level,onValueChange:c=>i({...n,debug:{level:c}}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"DEBUG",children:"DEBUG(调试)"}),e.jsx(te,{value:"INFO",children:"INFO(信息)"}),e.jsx(te,{value:"WARNING",children:"WARNING(警告)"}),e.jsx(te,{value:"ERROR",children:"ERROR(错误)"}),e.jsx(te,{value:"CRITICAL",children:"CRITICAL(严重)"})]})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"设置适配器的日志输出等级"})]})})]})})}const Sw=["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"],Cw=/^(aria-|data-)/,Bg=n=>Object.fromEntries(Object.entries(n).filter(([i])=>Cw.test(i)||Sw.includes(i)));function kw(n,i){const c=Bg(n);return Object.keys(n).some(d=>!Object.hasOwn(c,d)&&n[d]!==i[d])}class Tw extends u.Component{container;plugin;componentDidMount(){this.installPlugin()}componentDidUpdate(i){if(i.uppy!==this.props.uppy)this.uninstallPlugin(i),this.installPlugin();else if(kw(this.props,i)){const{uppy:c,...d}={...this.props,target:this.container};this.plugin.setOptions(d)}}componentWillUnmount(){this.uninstallPlugin()}installPlugin(){const{uppy:i,...c}={id:"Dashboard",...this.props,inline:!0,target:this.container};i.use(oy,c),this.plugin=i.getPlugin(c.id)}uninstallPlugin(i=this.props){const{uppy:c}=i;c.removePlugin(this.plugin)}render(){return u.createElement("div",{className:"uppy-Container",ref:i=>{this.container=i},...Bg(this.props)})}}function Ew({src:n,alt:i="表情包",className:c,maxRetries:d=5,retryInterval:h=1500}){const[f,x]=u.useState("loading"),[j,p]=u.useState(0),[w,v]=u.useState(null),y=u.useCallback(async()=>{try{const S=await fetch(n,{credentials:"include"});if(S.status===202){x("generating"),j{p(Y=>Y+1)},h):x("error");return}if(!S.ok){x("error");return}const k=await S.blob(),O=URL.createObjectURL(k);v(O),x("loaded")}catch(S){console.error("加载缩略图失败:",S),x("error")}},[n,j,d,h]);return u.useEffect(()=>{x("loading"),p(0),v(null)},[n]),u.useEffect(()=>{y()},[y]),u.useEffect(()=>()=>{w&&URL.revokeObjectURL(w)},[w]),f==="loading"||f==="generating"?e.jsx(Ng,{className:X("w-full h-full",c)}):f==="error"||!w?e.jsx("div",{className:X("w-full h-full flex items-center justify-center bg-muted",c),children:e.jsx(hg,{className:"h-8 w-8 text-muted-foreground"})}):e.jsx("img",{src:w,alt:i,className:X("w-full h-full object-contain",c)})}function zw({content:n,className:i=""}){return e.jsx("div",{className:`prose prose-sm dark:prose-invert max-w-none ${i}`,children:e.jsx(uy,{remarkPlugins:[hy,xy],rehypePlugins:[my],components:{code({inline:c,className:d,children:h,...f}){return c?e.jsx("code",{className:"bg-muted px-1.5 py-0.5 rounded text-sm font-mono",...f,children:h}):e.jsx("code",{className:`${d} block bg-muted p-4 rounded-lg overflow-x-auto`,...f,children:h})},table({children:c,...d}){return e.jsx("div",{className:"overflow-x-auto",children:e.jsx("table",{className:"border-collapse border border-border",...d,children:c})})},th({children:c,...d}){return e.jsx("th",{className:"border border-border bg-muted px-4 py-2 text-left font-semibold",...d,children:c})},td({children:c,...d}){return e.jsx("td",{className:"border border-border px-4 py-2",...d,children:c})},a({children:c,...d}){return e.jsx("a",{className:"text-primary hover:underline",target:"_blank",rel:"noopener noreferrer",...d,children:c})},blockquote({children:c,...d}){return e.jsx("blockquote",{className:"border-l-4 border-primary pl-4 italic text-muted-foreground",...d,children:c})},h1({children:c,...d}){return e.jsx("h1",{className:"text-3xl font-bold mt-6 mb-4",...d,children:c})},h2({children:c,...d}){return e.jsx("h2",{className:"text-2xl font-bold mt-5 mb-3",...d,children:c})},h3({children:c,...d}){return e.jsx("h3",{className:"text-xl font-bold mt-4 mb-2",...d,children:c})},h4({children:c,...d}){return e.jsx("h4",{className:"text-lg font-semibold mt-3 mb-2",...d,children:c})},ul({children:c,...d}){return e.jsx("ul",{className:"list-disc list-inside space-y-1 my-2",...d,children:c})},ol({children:c,...d}){return e.jsx("ol",{className:"list-decimal list-inside space-y-1 my-2",...d,children:c})},p({children:c,...d}){return e.jsx("p",{className:"my-2 leading-relaxed",...d,children:c})},hr({...c}){return e.jsx("hr",{className:"my-4 border-border",...c})}},children:n})})}function Aw({children:n,className:i}){return e.jsx(zw,{content:n,className:i})}const ga="/api/webui/emoji";async function Mw(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.is_registered!==void 0&&i.append("is_registered",n.is_registered.toString()),n.is_banned!==void 0&&i.append("is_banned",n.is_banned.toString()),n.format&&i.append("format",n.format),n.sort_by&&i.append("sort_by",n.sort_by),n.sort_order&&i.append("sort_order",n.sort_order);const c=await Te(`${ga}/list?${i}`,{});if(!c.ok)throw new Error(`获取表情包列表失败: ${c.statusText}`);return c.json()}async function Dw(n){const i=await Te(`${ga}/${n}`,{});if(!i.ok)throw new Error(`获取表情包详情失败: ${i.statusText}`);return i.json()}async function Ow(n,i){const c=await Te(`${ga}/${n}`,{method:"PATCH",body:JSON.stringify(i)});if(!c.ok)throw new Error(`更新表情包失败: ${c.statusText}`);return c.json()}async function Rw(n){const i=await Te(`${ga}/${n}`,{method:"DELETE"});if(!i.ok)throw new Error(`删除表情包失败: ${i.statusText}`);return i.json()}async function Lw(){const n=await Te(`${ga}/stats/summary`,{});if(!n.ok)throw new Error(`获取统计数据失败: ${n.statusText}`);return n.json()}async function Uw(n){const i=await Te(`${ga}/${n}/register`,{method:"POST"});if(!i.ok)throw new Error(`注册表情包失败: ${i.statusText}`);return i.json()}async function Bw(n){const i=await Te(`${ga}/${n}/ban`,{method:"POST"});if(!i.ok)throw new Error(`封禁表情包失败: ${i.statusText}`);return i.json()}function Hw(n,i=!1){return i?`${ga}/${n}/thumbnail?original=true`:`${ga}/${n}/thumbnail`}function qw(n){return`${ga}/${n}/thumbnail?original=true`}async function Gw(n){const i=await Te(`${ga}/batch/delete`,{method:"POST",body:JSON.stringify({emoji_ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除失败")}return i.json()}function Vw(){return`${ga}/upload`}function Fw(){const[n,i]=u.useState([]),[c,d]=u.useState(null),[h,f]=u.useState(!1),[x,j]=u.useState(1),[p,w]=u.useState(0),[v,y]=u.useState(20),[S,k]=u.useState("all"),[O,Y]=u.useState("all"),[L,R]=u.useState("all"),[H,D]=u.useState("usage_count"),[C,$]=u.useState("desc"),[G,T]=u.useState(null),[M,ne]=u.useState(!1),[fe,_e]=u.useState(!1),[Se,je]=u.useState(!1),[ye,be]=u.useState(new Set),[A,K]=u.useState(!1),[E,se]=u.useState(""),[_,me]=u.useState("medium"),[re,le]=u.useState(!1),{toast:pe}=Vs(),Ne=u.useCallback(async()=>{try{f(!0);const ue=await Mw({page:x,page_size:v,is_registered:S==="all"?void 0:S==="registered",is_banned:O==="all"?void 0:O==="banned",format:L==="all"?void 0:L,sort_by:H,sort_order:C});i(ue.data),w(ue.total)}catch(ue){const Ee=ue instanceof Error?ue.message:"加载表情包列表失败";pe({title:"错误",description:Ee,variant:"destructive"})}finally{f(!1)}},[x,v,S,O,L,H,C,pe]),he=async()=>{try{const ue=await Lw();d(ue.data)}catch(ue){console.error("加载统计数据失败:",ue)}};u.useEffect(()=>{Ne()},[Ne]),u.useEffect(()=>{he()},[]);const Q=async ue=>{try{const Ee=await Dw(ue.id);T(Ee.data),ne(!0)}catch(Ee){const as=Ee instanceof Error?Ee.message:"加载详情失败";pe({title:"错误",description:as,variant:"destructive"})}},P=ue=>{T(ue),_e(!0)},q=ue=>{T(ue),je(!0)},W=async()=>{if(G)try{await Rw(G.id),pe({title:"成功",description:"表情包已删除"}),je(!1),T(null),Ne(),he()}catch(ue){const Ee=ue instanceof Error?ue.message:"删除失败";pe({title:"错误",description:Ee,variant:"destructive"})}},Ce=async ue=>{try{await Uw(ue.id),pe({title:"成功",description:"表情包已注册"}),Ne(),he()}catch(Ee){const as=Ee instanceof Error?Ee.message:"注册失败";pe({title:"错误",description:as,variant:"destructive"})}},Me=async ue=>{try{await Bw(ue.id),pe({title:"成功",description:"表情包已封禁"}),Ne(),he()}catch(Ee){const as=Ee instanceof Error?Ee.message:"封禁失败";pe({title:"错误",description:as,variant:"destructive"})}},ce=ue=>{const Ee=new Set(ye);Ee.has(ue)?Ee.delete(ue):Ee.add(ue),be(Ee)},De=async()=>{try{const ue=await Gw(Array.from(ye));pe({title:"批量删除完成",description:ue.message}),be(new Set),K(!1),Ne(),he()}catch(ue){pe({title:"批量删除失败",description:ue instanceof Error?ue.message:"批量删除失败",variant:"destructive"})}},Fs=()=>{const ue=parseInt(E),Ee=Math.ceil(p/v);ue>=1&&ue<=Ee?(j(ue),se("")):pe({title:"无效的页码",description:`请输入1-${Ee}之间的页码`,variant:"destructive"})},Qs=c?.formats?Object.keys(c.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(N,{onClick:()=>le(!0),className:"gap-2",children:[e.jsx(fr,{className:"h-4 w-4"}),"上传表情包"]})]}),e.jsx(ss,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[c&&e.jsxs("div",{className:"grid gap-4 grid-cols-2 lg:grid-cols-4",children:[e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"总数"}),e.jsx(ws,{className:"text-2xl",children:c.total})]})}),e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"已注册"}),e.jsx(ws,{className:"text-2xl text-green-600",children:c.registered})]})}),e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"已封禁"}),e.jsx(ws,{className:"text-2xl text-red-600",children:c.banned})]})}),e.jsx(Ze,{children:e.jsxs(ys,{className:"pb-2",children:[e.jsx(ct,{children:"未注册"}),e.jsx(ws,{className:"text-2xl text-gray-600",children:c.unregistered})]})})]}),e.jsxs(Ze,{children:[e.jsx(ys,{children:e.jsxs(ws,{className:"flex items-center gap-2",children:[e.jsx(Ru,{className:"h-5 w-5"}),"筛选和排序"]})}),e.jsxs(Ts,{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(b,{children:"排序方式"}),e.jsxs(Be,{value:`${H}-${C}`,onValueChange:ue=>{const[Ee,as]=ue.split("-");D(Ee),$(as),j(1)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"usage_count-desc",children:"使用次数 (多→少)"}),e.jsx(te,{value:"usage_count-asc",children:"使用次数 (少→多)"}),e.jsx(te,{value:"register_time-desc",children:"注册时间 (新→旧)"}),e.jsx(te,{value:"register_time-asc",children:"注册时间 (旧→新)"}),e.jsx(te,{value:"record_time-desc",children:"记录时间 (新→旧)"}),e.jsx(te,{value:"record_time-asc",children:"记录时间 (旧→新)"}),e.jsx(te,{value:"last_used_time-desc",children:"最后使用 (新→旧)"}),e.jsx(te,{value:"last_used_time-asc",children:"最后使用 (旧→新)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"注册状态"}),e.jsxs(Be,{value:S,onValueChange:ue=>{k(ue),j(1)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部"}),e.jsx(te,{value:"registered",children:"已注册"}),e.jsx(te,{value:"unregistered",children:"未注册"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"封禁状态"}),e.jsxs(Be,{value:O,onValueChange:ue=>{Y(ue),j(1)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部"}),e.jsx(te,{value:"banned",children:"已封禁"}),e.jsx(te,{value:"unbanned",children:"未封禁"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"格式"}),e.jsxs(Be,{value:L,onValueChange:ue=>{R(ue),j(1)},children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部"}),Qs.map(ue=>e.jsxs(te,{value:ue,children:[ue.toUpperCase()," (",c?.formats[ue],")"]},ue))]})]})]})]}),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:[ye.size>0&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:["已选择 ",ye.size," 个表情包"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{className:"text-sm whitespace-nowrap",children:"卡片大小"}),e.jsxs(Be,{value:_,onValueChange:ue=>me(ue),children:[e.jsx(Le,{className:"w-24",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"small",children:"小"}),e.jsx(te,{value:"medium",children:"中"}),e.jsx(te,{value:"large",children:"大"})]})]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{htmlFor:"emoji-page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Be,{value:v.toString(),onValueChange:ue=>{y(parseInt(ue)),j(1),be(new Set)},children:[e.jsx(Le,{id:"emoji-page-size",className:"w-20",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"20",children:"20"}),e.jsx(te,{value:"40",children:"40"}),e.jsx(te,{value:"60",children:"60"}),e.jsx(te,{value:"100",children:"100"})]})]}),ye.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>be(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:()=>K(!0),children:[e.jsx(ts,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]}),e.jsx("div",{className:"flex justify-end pt-4 border-t",children:e.jsxs(N,{variant:"outline",size:"sm",onClick:Ne,disabled:h,children:[e.jsx(Ct,{className:`h-4 w-4 mr-2 ${h?"animate-spin":""}`}),"刷新"]})})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"表情包列表"}),e.jsxs(ct,{children:["共 ",p," 个表情包,当前第 ",x," 页"]})]}),e.jsxs(Ts,{children:[n.length===0?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:"暂无数据"}):e.jsx("div",{className:`grid gap-3 ${_==="small"?"grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10":_==="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(ue=>e.jsxs("div",{className:`group relative rounded-lg border bg-card overflow-hidden hover:ring-2 hover:ring-primary transition-all cursor-pointer ${ye.has(ue.id)?"ring-2 ring-primary bg-primary/5":""}`,onClick:()=>ce(ue.id),children:[e.jsx("div",{className:`absolute top-1 left-1 z-10 transition-opacity ${ye.has(ue.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 ${ye.has(ue.id)?"bg-primary border-primary text-primary-foreground":"bg-background/80 border-muted-foreground/50"}`,children:ye.has(ue.id)&&e.jsx(fa,{className:"h-3 w-3"})})}),e.jsxs("div",{className:"absolute top-1 right-1 z-10 flex flex-col gap-0.5",children:[ue.is_registered&&e.jsx($e,{variant:"default",className:"bg-green-600 text-[10px] px-1 py-0",children:"已注册"}),ue.is_banned&&e.jsx($e,{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 ${_==="small"?"p-1":_==="medium"?"p-2":"p-3"}`,children:e.jsx(Ew,{src:Hw(ue.id),alt:"表情包"})}),e.jsxs("div",{className:`border-t bg-card ${_==="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($e,{variant:"outline",className:"text-[10px] px-1 py-0",children:ue.format.toUpperCase()}),e.jsxs("span",{className:"font-mono",children:[ue.usage_count,"次"]})]}),e.jsxs("div",{className:`flex gap-1 justify-center opacity-0 group-hover:opacity-100 transition-opacity ${_==="small"?"flex-wrap":""}`,children:[e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:Ee=>{Ee.stopPropagation(),P(ue)},title:"编辑",children:e.jsx(mn,{className:"h-3 w-3"})}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:Ee=>{Ee.stopPropagation(),Q(ue)},title:"详情",children:e.jsx(La,{className:"h-3 w-3"})}),!ue.is_registered&&e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6 text-green-600 hover:text-green-700",onClick:Ee=>{Ee.stopPropagation(),Ce(ue)},title:"注册",children:e.jsx(fa,{className:"h-3 w-3"})}),!ue.is_banned&&e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6 text-orange-600 hover:text-orange-700",onClick:Ee=>{Ee.stopPropagation(),Me(ue)},title:"封禁",children:e.jsx(Eb,{className:"h-3 w-3"})}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-6 w-6 text-red-600 hover:text-red-700",onClick:Ee=>{Ee.stopPropagation(),q(ue)},title:"删除",children:e.jsx(ts,{className:"h-3 w-3"})})]})]})]},ue.id))}),p>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:["显示 ",(x-1)*v+1," 到"," ",Math.min(x*v,p)," 条,共 ",p," 条"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:x===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(ue=>Math.max(1,ue-1)),disabled:x===1,children:[e.jsx(Hl,{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:E,onChange:ue=>se(ue.target.value),onKeyDown:ue=>ue.key==="Enter"&&Fs(),placeholder:x.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(p/v)}),e.jsx(N,{variant:"outline",size:"sm",onClick:Fs,disabled:!E,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(ue=>ue+1),disabled:x>=Math.ceil(p/v),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(p/v)),disabled:x>=Math.ceil(p/v),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]}),e.jsx($w,{emoji:G,open:M,onOpenChange:ne}),e.jsx(Qw,{emoji:G,open:fe,onOpenChange:_e,onSuccess:()=>{Ne(),he()}}),e.jsx(Yw,{open:re,onOpenChange:le,onSuccess:()=>{Ne(),he()}})]})}),e.jsx(ps,{open:A,onOpenChange:K,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认批量删除"}),e.jsxs(us,{children:["你确定要删除选中的 ",ye.size," 个表情包吗?此操作不可撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:De,children:"确认删除"})]})]})}),e.jsx($s,{open:Se,onOpenChange:je,children:e.jsxs(Hs,{children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"确认删除"}),e.jsx(Is,{children:"确定要删除这个表情包吗?此操作无法撤销。"})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>je(!1),children:"取消"}),e.jsx(N,{variant:"destructive",onClick:W,children:"删除"})]})]})})]})}function $w({emoji:n,open:i,onOpenChange:c}){if(!n)return null;const d=h=>h?new Date(h*1e3).toLocaleString("zh-CN"):"-";return e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[90vh]",children:[e.jsx(qs,{children:e.jsx(Gs,{children:"表情包详情"})}),e.jsx(ss,{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:qw(n.id),alt:n.description||"表情包",className:"w-full h-full object-cover",onError:h=>{const f=h.target;f.style.display="none";const x=f.parentElement;x&&(x.innerHTML='')}})})}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"ID"}),e.jsx("div",{className:"mt-1 font-mono",children:n.id})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"格式"}),e.jsx("div",{className:"mt-1",children:e.jsx($e,{variant:"outline",children:n.format.toUpperCase()})})]})]}),e.jsxs("div",{children:[e.jsx(b,{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(b,{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(b,{className:"text-muted-foreground",children:"描述"}),n.description?e.jsx("div",{className:"mt-1 rounded-lg border bg-muted/50 p-3",children:e.jsx(Aw,{className:"prose-sm",children:n.description})}):e.jsx("div",{className:"mt-1 text-sm text-muted-foreground",children:"-"})]}),e.jsxs("div",{children:[e.jsx(b,{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(b,{className:"text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"mt-2 flex gap-2",children:[n.is_registered&&e.jsx($e,{variant:"default",className:"bg-green-600",children:"已注册"}),n.is_banned&&e.jsx($e,{variant:"destructive",children:"已封禁"}),!n.is_registered&&!n.is_banned&&e.jsx($e,{variant:"outline",children:"未注册"})]})]}),e.jsxs("div",{children:[e.jsx(b,{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(b,{className:"text-muted-foreground",children:"记录时间"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.record_time)})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"注册时间"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.register_time)})]})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-muted-foreground",children:"最后使用"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.last_used_time)})]})]})})]})})}function Qw({emoji:n,open:i,onOpenChange:c,onSuccess:d}){const[h,f]=u.useState(""),[x,j]=u.useState(!1),[p,w]=u.useState(!1),[v,y]=u.useState(!1),{toast:S}=Vs();u.useEffect(()=>{n&&(f(n.emotion||""),j(n.is_registered),w(n.is_banned))},[n]);const k=async()=>{if(n)try{y(!0);const O=h.split(/[,,]/).map(Y=>Y.trim()).filter(Boolean).join(",");await Ow(n.id,{emotion:O||void 0,is_registered:x,is_banned:p}),S({title:"成功",description:"表情包信息已更新"}),c(!1),d()}catch(O){const Y=O instanceof Error?O.message:"保存失败";S({title:"错误",description:Y,variant:"destructive"})}finally{y(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"编辑表情包"}),e.jsx(Is,{children:"修改表情包的情绪和状态信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(b,{children:"情绪"}),e.jsx(Bs,{value:h,onChange:O=>f(O.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:x,onCheckedChange:O=>{O===!0?(j(!0),w(!1)):j(!1)}}),e.jsx(b,{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:p,onCheckedChange:O=>{O===!0?(w(!0),j(!1)):w(!1)}}),e.jsx(b,{htmlFor:"is_banned",className:"cursor-pointer",children:"已封禁"})]})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:k,disabled:v,children:v?"保存中...":"保存"})]})]})}):null}function Yw({open:n,onOpenChange:i,onSuccess:c}){const[d,h]=u.useState("select"),[f,x]=u.useState([]),[j,p]=u.useState(null),[w,v]=u.useState(!1),{toast:y}=Vs(),S=u.useMemo(()=>new dy({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 G=()=>{const T=S.getFiles();if(T.length===0)return;const M=T.map(ne=>({id:ne.id,name:ne.name,previewUrl:ne.preview||URL.createObjectURL(ne.data),emotion:"",description:"",isRegistered:!0,file:ne.data}));x(M),T.length===1?(p(M[0].id),h("edit-single")):h("edit-multiple")};return S.on("upload",G),()=>{S.off("upload",G)}},[S]),u.useEffect(()=>{n||(S.cancelAll(),h("select"),x([]),p(null),v(!1))},[n,S]);const k=u.useCallback((G,T)=>{x(M=>M.map(ne=>ne.id===G?{...ne,...T}:ne))},[]),O=u.useCallback(G=>G.emotion.trim().length>0,[]),Y=u.useMemo(()=>f.length>0&&f.every(O),[f,O]),L=u.useMemo(()=>f.find(G=>G.id===j)||null,[f,j]),R=u.useCallback(()=>{(d==="edit-single"||d==="edit-multiple")&&(h("select"),x([]),p(null))},[d]),H=u.useCallback(async()=>{if(!Y){y({title:"请填写必填项",description:"每个表情包的情感标签都是必填的",variant:"destructive"});return}v(!0);const G=localStorage.getItem("access-token")||"";let T=0,M=0;try{for(const ne of f){const fe=new FormData;fe.append("file",ne.file),fe.append("emotion",ne.emotion),fe.append("description",ne.description),fe.append("is_registered",ne.isRegistered.toString());try{(await fetch(Vw(),{method:"POST",headers:{Authorization:`Bearer ${G}`},body:fe})).ok?T++:M++}catch{M++}}M===0?(y({title:"上传成功",description:`成功上传 ${T} 个表情包`}),i(!1),c()):(y({title:"部分上传失败",description:`成功 ${T} 个,失败 ${M} 个`,variant:"destructive"}),c())}finally{v(!1)}},[Y,f,y,i,c]),D=()=>e.jsx("div",{className:"space-y-4",children:e.jsx("div",{className:"border rounded-lg overflow-hidden w-full",children:e.jsx(Tw,{uppy:S,proudlyDisplayPoweredByUppy:!1,hideProgressDetails:!0,height:350,width:"100%",theme:"auto",note:"支持 JPG、PNG、GIF、WebP 格式,最多 20 个文件"})})}),C=()=>{const G=f[0];return G?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs(N,{variant:"ghost",size:"sm",onClick:R,children:[e.jsx(ii,{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:G.previewUrl,alt:G.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:G.name})]}),e.jsxs("div",{className:"flex-1 space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"single-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"single-emotion",value:G.emotion,onChange:T=>k(G.id,{emotion:T.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:G.emotion.trim()?"":"border-destructive"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"用于情感匹配,多个标签用逗号分隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"single-description",children:"描述"}),e.jsx(ie,{id:"single-description",value:G.description,onChange:T=>k(G.id,{description:T.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"single-is-registered",checked:G.isRegistered,onCheckedChange:T=>k(G.id,{isRegistered:T===!0})}),e.jsx(b,{htmlFor:"single-is-registered",className:"cursor-pointer",children:"上传后立即注册(可被麦麦使用)"})]})]})]}),e.jsx(at,{children:e.jsx(N,{onClick:H,disabled:!Y||w,children:w?"上传中...":"上传"})})]}):null},$=()=>{const G=f.filter(O).length,T=f.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(N,{variant:"ghost",size:"sm",onClick:R,children:[e.jsx(ii,{className:"h-4 w-4 mr-1"}),"返回"]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["编辑表情包信息(",G,"/",T," 已完成)"]})]}),e.jsx($e,{variant:Y?"default":"secondary",children:Y?e.jsxs(e.Fragment,{children:[e.jsx($t,{className:"h-3 w-3 mr-1"}),"全部完成"]}):e.jsxs(e.Fragment,{children:[e.jsx(dl,{className:"h-3 w-3 mr-1"}),"未完成"]})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(ss,{className:"h-[350px] pr-2",children:e.jsx("div",{className:"space-y-2",children:f.map(M=>{const ne=O(M),fe=j===M.id;return e.jsxs("div",{onClick:()=>p(M.id),className:` flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all - ${xe?"ring-2 ring-primary":""} + ${fe?"ring-2 ring-primary":""} ${ne?"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:D.previewUrl,alt:D.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:D.name}),e.jsx("p",{className:"text-xs text-muted-foreground truncate",children:D.emotion||"未填写情感标签"})]}),ne?e.jsx(fa,{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"})]},D.id)})})}),e.jsx("div",{className:"border rounded-lg p-4",children:U?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:U.previewUrl,alt:U.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:U.name}),M(U)&&e.jsxs(Ye,{variant:"outline",className:"text-green-600 border-green-600",children:[e.jsx(sa,{className:"h-3 w-3 mr-1"}),"已完成"]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"multi-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(oe,{id:"multi-emotion",value:U.emotion,onChange:D=>C(U.id,{emotion:D.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:U.emotion.trim()?"":"border-destructive"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"multi-description",children:"描述"}),e.jsx(oe,{id:"multi-description",value:U.description,onChange:D=>C(U.id,{description:D.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"multi-is-registered",checked:U.isRegistered,onCheckedChange:D=>C(U.id,{isRegistered:D===!0})}),e.jsx(b,{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(dg,{className:"h-12 w-12 mx-auto mb-2 opacity-50"}),e.jsx("p",{children:"点击左侧卡片编辑"})]})})})]}),e.jsx(at,{children:e.jsx(N,{onClick:K,disabled:!F||w,children:w?"上传中...":`上传全部 (${T})`})})]})};return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Bs,{className:"max-w-3xl max-h-[90vh] overflow-hidden",children:[e.jsxs(Hs,{children:[e.jsxs(qs,{className:"flex items-center gap-2",children:[e.jsx(fr,{className:"h-5 w-5"}),d==="select"&&"上传表情包 - 选择文件",d==="edit-single"&&"上传表情包 - 填写信息",d==="edit-multiple"&&"上传表情包 - 批量编辑"]}),e.jsxs(Is,{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"&&H(),d==="edit-single"&&A(),d==="edit-multiple"&&V()]})]})})}const Gl="/api/webui/expression";async function Hw(){const n=await Te(`${Gl}/chats`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取聊天列表失败")}return n.json()}async function qw(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.chat_id&&i.append("chat_id",n.chat_id);const c=await Te(`${Gl}/list?${i}`,{});if(!c.ok){const d=await c.json();throw new Error(d.detail||"获取表达方式列表失败")}return c.json()}async function Gw(n){const i=await Te(`${Gl}/${n}`,{});if(!i.ok){const c=await i.json();throw new Error(c.detail||"获取表达方式详情失败")}return i.json()}async function Vw(n){const i=await Te(`${Gl}/`,{method:"POST",body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"创建表达方式失败")}return i.json()}async function Fw(n,i){const c=await Te(`${Gl}/${n}`,{method:"PATCH",body:JSON.stringify(i)});if(!c.ok){const d=await c.json();throw new Error(d.detail||"更新表达方式失败")}return c.json()}async function $w(n){const i=await Te(`${Gl}/${n}`,{method:"DELETE"});if(!i.ok){const c=await i.json();throw new Error(c.detail||"删除表达方式失败")}return i.json()}async function Qw(n){const i=await Te(`${Gl}/batch/delete`,{method:"POST",body:JSON.stringify({ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除表达方式失败")}return i.json()}async function Yw(){const n=await Te(`${Gl}/stats/summary`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取统计数据失败")}return n.json()}function Xw(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,x]=u.useState(0),[f,j]=u.useState(1),[p,w]=u.useState(20),[v,y]=u.useState(""),[S,C]=u.useState(null),[M,F]=u.useState(!1),[U,O]=u.useState(!1),[K,H]=u.useState(!1),[A,V]=u.useState(null),[Q,T]=u.useState(new Set),[D,ne]=u.useState(!1),[xe,_e]=u.useState(""),[Se,ge]=u.useState({total:0,recent_7days:0,chat_count:0,top_chats:{}}),[ye,be]=u.useState([]),[z,X]=u.useState(new Map),{toast:k}=Gs(),se=async()=>{try{d(!0);const W=await qw({page:f,page_size:p,search:v||void 0});i(W.data),x(W.total)}catch(W){k({title:"加载失败",description:W instanceof Error?W.message:"无法加载表达方式",variant:"destructive"})}finally{d(!1)}},_=async()=>{try{const W=await Yw();W?.data&&ge(W.data)}catch(W){console.error("加载统计数据失败:",W)}},ue=async()=>{try{const W=await Hw();if(W?.data){be(W.data);const Ce=new Map;W.data.forEach(Me=>{Ce.set(Me.chat_id,Me.chat_name)}),X(Ce)}}catch(W){console.error("加载聊天列表失败:",W)}},ie=W=>z.get(W)||W;u.useEffect(()=>{se(),_(),ue()},[f,p,v]);const ae=async W=>{try{const Ce=await Gw(W.id);C(Ce.data),F(!0)}catch(Ce){k({title:"加载详情失败",description:Ce instanceof Error?Ce.message:"无法加载表达方式详情",variant:"destructive"})}},fe=W=>{C(W),O(!0)},Ne=async W=>{try{await $w(W.id),k({title:"删除成功",description:`已删除表达方式: ${W.situation}`}),V(null),se(),_()}catch(Ce){k({title:"删除失败",description:Ce instanceof Error?Ce.message:"无法删除表达方式",variant:"destructive"})}},me=W=>{const Ce=new Set(Q);Ce.has(W)?Ce.delete(W):Ce.add(W),T(Ce)},G=()=>{Q.size===n.length&&n.length>0?T(new Set):T(new Set(n.map(W=>W.id)))},P=async()=>{try{await Qw(Array.from(Q)),k({title:"批量删除成功",description:`已删除 ${Q.size} 个表达方式`}),T(new Set),ne(!1),se(),_()}catch(W){k({title:"批量删除失败",description:W instanceof Error?W.message:"无法批量删除表达方式",variant:"destructive"})}},B=()=>{const W=parseInt(xe),Ce=Math.ceil(h/p);W>=1&&W<=Ce?(j(W),_e("")):k({title:"无效的页码",description:`请输入1-${Ce}之间的页码`,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(un,{className:"h-8 w-8",strokeWidth:2}),"表达方式管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦的表达方式和话术模板"})]}),e.jsxs(N,{onClick:()=>H(!0),className:"gap-2",children:[e.jsx(xt,{className:"h-4 w-4"}),"新增表达方式"]})]})}),e.jsx(ss,{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(b,{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(zt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{id:"search",placeholder:"搜索情境、风格或上下文...",value:v,onChange:W=>y(W.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:Q.size>0&&e.jsxs("span",{children:["已选择 ",Q.size," 个表达方式"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(He,{value:p.toString(),onValueChange:W=>{w(parseInt(W)),j(1),T(new Set)},children:[e.jsx(Le,{id:"page-size",className:"w-20",children:e.jsx(qe,{})}),e.jsxs(Ue,{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"})]})]}),Q.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>T(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:()=>ne(!0),children:[e.jsx(ls,{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(hn,{children:[e.jsx(xn,{children:e.jsxs(ot,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:Q.size===n.length&&n.length>0,onCheckedChange:G})}),e.jsx(Ie,{children:"情境"}),e.jsx(Ie,{children:"风格"}),e.jsx(Ie,{children:"聊天"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c?e.jsx(ot,{children:e.jsx(Fe,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(ot,{children:e.jsx(Fe,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(W=>e.jsxs(ot,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:Q.has(W.id),onCheckedChange:()=>me(W.id)})}),e.jsx(Fe,{className:"font-medium max-w-xs truncate",children:W.situation}),e.jsx(Fe,{className:"max-w-xs truncate",children:W.style}),e.jsx(Fe,{className:"max-w-[200px] truncate",title:ie(W.chat_id),style:{wordBreak:"keep-all"},children:e.jsx("span",{className:"whitespace-nowrap overflow-hidden text-ellipsis block",children:ie(W.chat_id)})}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>fe(W),children:[e.jsx(mn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>ae(W),title:"查看详情",children:e.jsx(Dt,{className:"h-4 w-4"})}),e.jsxs(N,{size:"sm",onClick:()=>V(W),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ls,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},W.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:c?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(W=>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:Q.has(W.id),onCheckedChange:()=>me(W.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:W.situation,children:W.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:W.style,children:W.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:ie(W.chat_id),style:{wordBreak:"keep-all"},children:ie(W.chat_id)})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>fe(W),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(mn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>ae(W),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:e.jsx(Dt,{className:"h-3 w-3"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>V(W),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(ls,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},W.id))}),h>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:["共 ",h," 条记录,第 ",f," / ",Math.ceil(h/p)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(f-1),disabled:f===1,children:[e.jsx(Hl,{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(oe,{type:"number",value:xe,onChange:W=>_e(W.target.value),onKeyDown:W=>W.key==="Enter"&&B(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(h/p)}),e.jsx(N,{variant:"outline",size:"sm",onClick:B,disabled:!xe,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(f+1),disabled:f>=Math.ceil(h/p),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(h/p)),disabled:f>=Math.ceil(h/p),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(Kw,{expression:S,open:M,onOpenChange:F,chatNameMap:z}),e.jsx(Jw,{open:K,onOpenChange:H,chatList:ye,onSuccess:()=>{se(),_(),H(!1)}}),e.jsx(Zw,{expression:S,open:U,onOpenChange:O,chatList:ye,onSuccess:()=>{se(),_(),O(!1)}}),e.jsx(ps,{open:!!A,onOpenChange:()=>V(null),children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除表达方式 "',A?.situation,'" 吗? 此操作不可撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>A&&Ne(A),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(Iw,{open:D,onOpenChange:ne,onConfirm:P,count:Q.size})]})}function Kw({expression:n,open:i,onOpenChange:c,chatNameMap:d}){if(!n)return null;const h=f=>f?new Date(f*1e3).toLocaleString("zh-CN"):"-",x=f=>d.get(f)||f;return e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"表达方式详情"}),e.jsx(Is,{children:"查看表达方式的完整信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(rr,{label:"情境",value:n.situation}),e.jsx(rr,{label:"风格",value:n.style}),e.jsx(rr,{label:"聊天",value:x(n.chat_id)}),e.jsx(rr,{icon:ri,label:"记录ID",value:n.id.toString(),mono:!0})]}),e.jsx("div",{className:"grid grid-cols-2 gap-4",children:e.jsx(rr,{icon:li,label:"创建时间",value:h(n.create_date)})})]}),e.jsx(at,{children:e.jsx(N,{onClick:()=>c(!1),children:"关闭"})})]})})}function rr({icon:n,label:i,value:c,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(b,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:$("text-sm",d&&"font-mono",!c&&"text-muted-foreground"),children:c||"-"})]})}function Jw({open:n,onOpenChange:i,chatList:c,onSuccess:d}){const[h,x]=u.useState({situation:"",style:"",chat_id:""}),[f,j]=u.useState(!1),{toast:p}=Gs(),w=async()=>{if(!h.situation||!h.style||!h.chat_id){p({title:"验证失败",description:"请填写必填字段:情境、风格和聊天",variant:"destructive"});return}try{j(!0),await Vw(h),p({title:"创建成功",description:"表达方式已创建"}),x({situation:"",style:"",chat_id:""}),d()}catch(v){p({title:"创建失败",description:v instanceof Error?v.message:"无法创建表达方式",variant:"destructive"})}finally{j(!1)}};return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"新增表达方式"}),e.jsx(Is,{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(b,{htmlFor:"situation",children:["情境 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(oe,{id:"situation",value:h.situation,onChange:v=>x({...h,situation:v.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"style",children:["风格 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(oe,{id:"style",value:h.style,onChange:v=>x({...h,style:v.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(He,{value:h.chat_id,onValueChange:v=>x({...h,chat_id:v}),children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{children:c.map(v=>e.jsx(le,{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(N,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(N,{onClick:w,disabled:f,children:f?"创建中...":"创建"})]})]})})}function Zw({expression:n,open:i,onOpenChange:c,chatList:d,onSuccess:h}){const[x,f]=u.useState({}),[j,p]=u.useState(!1),{toast:w}=Gs();u.useEffect(()=>{n&&f({situation:n.situation,style:n.style,chat_id:n.chat_id})},[n]);const v=async()=>{if(n)try{p(!0),await Fw(n.id,x),w({title:"保存成功",description:"表达方式已更新"}),h()}catch(y){w({title:"保存失败",description:y instanceof Error?y.message:"无法更新表达方式",variant:"destructive"})}finally{p(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"编辑表达方式"}),e.jsx(Is,{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(b,{htmlFor:"edit_situation",children:"情境"}),e.jsx(oe,{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(b,{htmlFor:"edit_style",children:"风格"}),e.jsx(oe,{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(b,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(He,{value:x.chat_id||"",onValueChange:y=>f({...x,chat_id:y}),children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{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(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:v,disabled:j,children:j?"保存中...":"保存"})]})]})}):null}function Iw({open:n,onOpenChange:i,onConfirm:c,count:d}){return e.jsx(ps,{open:n,onOpenChange:i,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认批量删除"}),e.jsxs(ds,{children:["您即将删除 ",d," 个表达方式,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:c,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})}const ml="/api/webui/jargon";async function Pw(){const n=await Te(`${ml}/chats`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取聊天列表失败")}return n.json()}async function Ww(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.chat_id&&i.append("chat_id",n.chat_id),n.is_jargon!==void 0&&n.is_jargon!==null&&i.append("is_jargon",n.is_jargon.toString()),n.is_global!==void 0&&i.append("is_global",n.is_global.toString());const c=await Te(`${ml}/list?${i}`,{});if(!c.ok){const d=await c.json();throw new Error(d.detail||"获取黑话列表失败")}return c.json()}async function e1(n){const i=await Te(`${ml}/${n}`,{});if(!i.ok){const c=await i.json();throw new Error(c.detail||"获取黑话详情失败")}return i.json()}async function s1(n){const i=await Te(`${ml}/`,{method:"POST",body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"创建黑话失败")}return i.json()}async function t1(n,i){const c=await Te(`${ml}/${n}`,{method:"PATCH",body:JSON.stringify(i)});if(!c.ok){const d=await c.json();throw new Error(d.detail||"更新黑话失败")}return c.json()}async function a1(n){const i=await Te(`${ml}/${n}`,{method:"DELETE"});if(!i.ok){const c=await i.json();throw new Error(c.detail||"删除黑话失败")}return i.json()}async function l1(n){const i=await Te(`${ml}/batch/delete`,{method:"POST",body:JSON.stringify({ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除黑话失败")}return i.json()}async function n1(){const n=await Te(`${ml}/stats/summary`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取黑话统计失败")}return n.json()}async function i1(n,i){const c=new URLSearchParams;n.forEach(h=>c.append("ids",h.toString())),c.append("is_jargon",i.toString());const d=await Te(`${ml}/batch/set-jargon?${c}`,{method:"POST"});if(!d.ok){const h=await d.json();throw new Error(h.detail||"批量设置黑话状态失败")}return d.json()}function r1(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,x]=u.useState(0),[f,j]=u.useState(1),[p,w]=u.useState(20),[v,y]=u.useState(""),[S,C]=u.useState("all"),[M,F]=u.useState("all"),[U,O]=u.useState(null),[K,H]=u.useState(!1),[A,V]=u.useState(!1),[Q,T]=u.useState(!1),[D,ne]=u.useState(null),[xe,_e]=u.useState(new Set),[Se,ge]=u.useState(!1),[ye,be]=u.useState(""),[z,X]=u.useState({total:0,confirmed_jargon:0,confirmed_not_jargon:0,pending:0,global_count:0,complete_count:0,chat_count:0,top_chats:{}}),[k,se]=u.useState([]),{toast:_}=Gs(),ue=async()=>{try{d(!0);const re=await Ww({page:f,page_size:p,search:v||void 0,chat_id:S==="all"?void 0:S,is_jargon:M==="all"?void 0:M==="true"?!0:M==="false"?!1:void 0});i(re.data),x(re.total)}catch(re){_({title:"加载失败",description:re instanceof Error?re.message:"无法加载黑话列表",variant:"destructive"})}finally{d(!1)}},ie=async()=>{try{const re=await n1();re?.data&&X(re.data)}catch(re){console.error("加载统计数据失败:",re)}},ae=async()=>{try{const re=await Pw();re?.data&&se(re.data)}catch(re){console.error("加载聊天列表失败:",re)}};u.useEffect(()=>{ue(),ie(),ae()},[f,p,v,S,M]);const fe=async re=>{try{const De=await e1(re.id);O(De.data),H(!0)}catch(De){_({title:"加载详情失败",description:De instanceof Error?De.message:"无法加载黑话详情",variant:"destructive"})}},Ne=re=>{O(re),V(!0)},me=async re=>{try{await a1(re.id),_({title:"删除成功",description:`已删除黑话: ${re.content}`}),ne(null),ue(),ie()}catch(De){_({title:"删除失败",description:De instanceof Error?De.message:"无法删除黑话",variant:"destructive"})}},G=re=>{const De=new Set(xe);De.has(re)?De.delete(re):De.add(re),_e(De)},P=()=>{xe.size===n.length&&n.length>0?_e(new Set):_e(new Set(n.map(re=>re.id)))},B=async()=>{try{await l1(Array.from(xe)),_({title:"批量删除成功",description:`已删除 ${xe.size} 个黑话`}),_e(new Set),ge(!1),ue(),ie()}catch(re){_({title:"批量删除失败",description:re instanceof Error?re.message:"无法批量删除黑话",variant:"destructive"})}},W=async re=>{try{await i1(Array.from(xe),re),_({title:"操作成功",description:`已将 ${xe.size} 个词条设为${re?"黑话":"非黑话"}`}),_e(new Set),ue(),ie()}catch(De){_({title:"操作失败",description:De instanceof Error?De.message:"批量设置失败",variant:"destructive"})}},Ce=()=>{const re=parseInt(ye),De=Math.ceil(h/p);re>=1&&re<=De?(j(re),be("")):_({title:"无效的页码",description:`请输入1-${De}之间的页码`,variant:"destructive"})},Me=re=>re===!0?e.jsxs(Ye,{variant:"default",className:"bg-green-600 hover:bg-green-700",children:[e.jsx(sa,{className:"h-3 w-3 mr-1"}),"是黑话"]}):re===!1?e.jsxs(Ye,{variant:"secondary",children:[e.jsx(dl,{className:"h-3 w-3 mr-1"}),"非黑话"]}):e.jsxs(Ye,{variant:"outline",children:[e.jsx(og,{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(Cb,{className:"h-8 w-8",strokeWidth:2}),"黑话管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦学习到的黑话和俚语"})]}),e.jsxs(N,{onClick:()=>T(!0),className:"gap-2",children:[e.jsx(xt,{className:"h-4 w-4"}),"新增黑话"]})]})}),e.jsx(ss,{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:z.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:z.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:z.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:z.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:z.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:z.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:z.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(b,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{id:"search",placeholder:"搜索内容、含义...",value:v,onChange:re=>y(re.target.value),className:"pl-9"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(b,{children:"聊天筛选"}),e.jsxs(He,{value:S,onValueChange:C,children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"全部聊天"})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"all",children:"全部聊天"}),k.map(re=>e.jsx(le,{value:re.chat_id,children:re.chat_name},re.chat_id))]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(b,{children:"状态筛选"}),e.jsxs(He,{value:M,onValueChange:F,children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"全部状态"})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"all",children:"全部状态"}),e.jsx(le,{value:"true",children:"是黑话"}),e.jsx(le,{value:"false",children:"非黑话"}),e.jsx(le,{value:"null",children:"未判定"})]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(b,{htmlFor:"page-size",children:"每页显示"}),e.jsxs(He,{value:p.toString(),onValueChange:re=>{w(parseInt(re)),j(1),_e(new Set)},children:[e.jsx(Le,{id:"page-size",children:e.jsx(qe,{})}),e.jsxs(Ue,{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"})]})]})]})]}),xe.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:["已选择 ",xe.size," 个"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>W(!0),children:[e.jsx(sa,{className:"h-4 w-4 mr-1"}),"标记为黑话"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>W(!1),children:[e.jsx(dl,{className:"h-4 w-4 mr-1"}),"标记为非黑话"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>_e(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:()=>ge(!0),children:[e.jsx(ls,{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(hn,{children:[e.jsx(xn,{children:e.jsxs(ot,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:xe.size===n.length&&n.length>0,onCheckedChange:P})}),e.jsx(Ie,{children:"内容"}),e.jsx(Ie,{children:"含义"}),e.jsx(Ie,{children:"聊天"}),e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{className:"text-center",children:"次数"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c?e.jsx(ot,{children:e.jsx(Fe,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(ot,{children:e.jsx(Fe,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(re=>e.jsxs(ot,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:xe.has(re.id),onCheckedChange:()=>G(re.id)})}),e.jsx(Fe,{className:"font-medium max-w-[200px]",children:e.jsxs("div",{className:"flex items-center gap-2",children:[re.is_global&&e.jsx("span",{title:"全局黑话",children:e.jsx(Du,{className:"h-4 w-4 text-blue-500 flex-shrink-0"})}),e.jsx("span",{className:"truncate",title:re.content,children:re.content})]})}),e.jsx(Fe,{className:"max-w-[200px] truncate",title:re.meaning||"",children:re.meaning||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Fe,{className:"max-w-[150px] truncate",title:re.chat_name||re.chat_id,children:re.chat_name||re.chat_id}),e.jsx(Fe,{children:Me(re.is_jargon)}),e.jsx(Fe,{className:"text-center",children:re.count}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>Ne(re),children:[e.jsx(mn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>fe(re),title:"查看详情",children:e.jsx(Dt,{className:"h-4 w-4"})}),e.jsxs(N,{size:"sm",onClick:()=>ne(re),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ls,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},re.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:c?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(re=>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:xe.has(re.id),onCheckedChange:()=>G(re.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:[re.is_global&&e.jsx(Du,{className:"h-4 w-4 text-blue-500 flex-shrink-0"}),e.jsx("h3",{className:"font-semibold text-sm break-all",children:re.content})]}),re.meaning&&e.jsx("p",{className:"text-sm text-muted-foreground break-all",children:re.meaning}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[Me(re.is_jargon),e.jsxs("span",{className:"text-muted-foreground",children:["次数: ",re.count]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate",children:["聊天: ",re.chat_name||re.chat_id]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>Ne(re),className:"text-xs px-2 py-1 h-auto",children:[e.jsx(mn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>fe(re),className:"text-xs px-2 py-1 h-auto",children:e.jsx(Dt,{className:"h-3 w-3"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>ne(re),className:"text-xs px-2 py-1 h-auto text-destructive hover:text-destructive",children:[e.jsx(ls,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},re.id))}),h>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:["共 ",h," 条记录,第 ",f," / ",Math.ceil(h/p)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(f-1),disabled:f===1,children:[e.jsx(Hl,{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(oe,{type:"number",value:ye,onChange:re=>be(re.target.value),onKeyDown:re=>re.key==="Enter"&&Ce(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(h/p)}),e.jsx(N,{variant:"outline",size:"sm",onClick:Ce,disabled:!ye,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(f+1),disabled:f>=Math.ceil(h/p),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(h/p)),disabled:f>=Math.ceil(h/p),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(c1,{jargon:U,open:K,onOpenChange:H}),e.jsx(o1,{open:Q,onOpenChange:T,chatList:k,onSuccess:()=>{ue(),ie(),T(!1)}}),e.jsx(d1,{jargon:U,open:A,onOpenChange:V,chatList:k,onSuccess:()=>{ue(),ie(),V(!1)}}),e.jsx(ps,{open:!!D,onOpenChange:()=>ne(null),children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除黑话 "',D?.content,'" 吗?此操作不可撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>D&&me(D),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(ps,{open:Se,onOpenChange:ge,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认批量删除"}),e.jsxs(ds,{children:["您即将删除 ",xe.size," 个黑话,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:B,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})]})}function c1({jargon:n,open:i,onOpenChange:c}){return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] grid grid-rows-[auto_1fr_auto] overflow-hidden",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"黑话详情"}),e.jsx(Is,{children:"查看黑话的完整信息"})]}),e.jsx(ss,{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(Au,{icon:ri,label:"记录ID",value:n.id.toString(),mono:!0}),e.jsx(Au,{label:"使用次数",value:n.count.toString()})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{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(b,{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((h,x)=>e.jsxs("div",{children:[x>0&&e.jsx("hr",{className:"my-3 border-border"}),e.jsx("div",{className:"whitespace-pre-wrap",children:h})]},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(b,{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.meaning||"-"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Au,{label:"聊天",value:n.chat_name||n.chat_id}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{className:"text-xs text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"flex items-center gap-2",children:[n.is_jargon===!0&&e.jsx(Ye,{variant:"default",className:"bg-green-600",children:"是黑话"}),n.is_jargon===!1&&e.jsx(Ye,{variant:"secondary",children:"非黑话"}),n.is_jargon===null&&e.jsx(Ye,{variant:"outline",children:"未判定"}),n.is_global&&e.jsx(Ye,{variant:"outline",className:"border-blue-500 text-blue-500",children:"全局"}),n.is_complete&&e.jsx(Ye,{variant:"outline",className:"border-purple-500 text-purple-500",children:"推断完成"})]})]})]}),n.inference_with_context&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{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(b,{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(at,{className:"flex-shrink-0",children:e.jsx(N,{onClick:()=>c(!1),children:"关闭"})})]})}):null}function Au({icon:n,label:i,value:c,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(b,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:$("text-sm",d&&"font-mono",!c&&"text-muted-foreground"),children:c||"-"})]})}function o1({open:n,onOpenChange:i,chatList:c,onSuccess:d}){const[h,x]=u.useState({content:"",meaning:"",chat_id:"",is_global:!1}),[f,j]=u.useState(!1),{toast:p}=Gs(),w=async()=>{if(!h.content||!h.chat_id){p({title:"验证失败",description:"请填写必填字段:内容和聊天",variant:"destructive"});return}try{j(!0),await s1(h),p({title:"创建成功",description:"黑话已创建"}),x({content:"",meaning:"",chat_id:"",is_global:!1}),d()}catch(v){p({title:"创建失败",description:v instanceof Error?v.message:"无法创建黑话",variant:"destructive"})}finally{j(!1)}};return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"新增黑话"}),e.jsx(Is,{children:"创建新的黑话记录"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"content",children:["内容 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(oe,{id:"content",value:h.content,onChange:v=>x({...h,content:v.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"meaning",children:"含义"}),e.jsx(Fs,{id:"meaning",value:h.meaning||"",onChange:v=>x({...h,meaning:v.target.value}),placeholder:"输入黑话含义(可选)",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(He,{value:h.chat_id,onValueChange:v=>x({...h,chat_id:v}),children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{children:c.map(v=>e.jsx(le,{value:v.chat_id,children:v.chat_name},v.chat_id))})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Xe,{id:"is_global",checked:h.is_global,onCheckedChange:v=>x({...h,is_global:v})}),e.jsx(b,{htmlFor:"is_global",children:"设为全局黑话"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(N,{onClick:w,disabled:f,children:f?"创建中...":"创建"})]})]})})}function d1({jargon:n,open:i,onOpenChange:c,chatList:d,onSuccess:h}){const[x,f]=u.useState({}),[j,p]=u.useState(!1),{toast:w}=Gs();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 v=async()=>{if(n)try{p(!0),await t1(n.id,x),w({title:"保存成功",description:"黑话已更新"}),h()}catch(y){w({title:"保存失败",description:y instanceof Error?y.message:"无法更新黑话",variant:"destructive"})}finally{p(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"编辑黑话"}),e.jsx(Is,{children:"修改黑话的信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit_content",children:"内容"}),e.jsx(oe,{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(b,{htmlFor:"edit_meaning",children:"含义"}),e.jsx(Fs,{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(b,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(He,{value:x.chat_id||"",onValueChange:y=>f({...x,chat_id:y}),children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{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(b,{children:"黑话状态"}),e.jsxs(He,{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(Le,{children:e.jsx(qe,{})}),e.jsxs(Ue,{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(Xe,{id:"edit_is_global",checked:x.is_global,onCheckedChange:y=>f({...x,is_global:y})}),e.jsx(b,{htmlFor:"edit_is_global",children:"全局黑话"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:v,disabled:j,children:j?"保存中...":"保存"})]})]})}):null}const mi="/api/webui/person";async function u1(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.is_known!==void 0&&i.append("is_known",n.is_known.toString()),n.platform&&i.append("platform",n.platform);const c=await Te(`${mi}/list?${i}`,{headers:Ls()});if(!c.ok){const d=await c.json();throw new Error(d.detail||"获取人物列表失败")}return c.json()}async function m1(n){const i=await Te(`${mi}/${n}`,{headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"获取人物详情失败")}return i.json()}async function h1(n,i){const c=await Te(`${mi}/${n}`,{method:"PATCH",headers:Ls(),body:JSON.stringify(i)});if(!c.ok){const d=await c.json();throw new Error(d.detail||"更新人物信息失败")}return c.json()}async function x1(n){const i=await Te(`${mi}/${n}`,{method:"DELETE",headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"删除人物信息失败")}return i.json()}async function f1(){const n=await Te(`${mi}/stats/summary`,{headers:Ls()});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取统计数据失败")}return n.json()}async function p1(n){const i=await Te(`${mi}/batch/delete`,{method:"POST",headers:Ls(),body:JSON.stringify({person_ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除失败")}return i.json()}function g1(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,x]=u.useState(0),[f,j]=u.useState(1),[p,w]=u.useState(20),[v,y]=u.useState(""),[S,C]=u.useState(void 0),[M,F]=u.useState(void 0),[U,O]=u.useState(null),[K,H]=u.useState(!1),[A,V]=u.useState(!1),[Q,T]=u.useState(null),[D,ne]=u.useState({total:0,known:0,unknown:0,platforms:{}}),[xe,_e]=u.useState(new Set),[Se,ge]=u.useState(!1),[ye,be]=u.useState(""),{toast:z}=Gs(),X=async()=>{try{d(!0);const B=await u1({page:f,page_size:p,search:v||void 0,is_known:S,platform:M});i(B.data),x(B.total)}catch(B){z({title:"加载失败",description:B instanceof Error?B.message:"无法加载人物信息",variant:"destructive"})}finally{d(!1)}},k=async()=>{try{const B=await f1();B?.data&&ne(B.data)}catch(B){console.error("加载统计数据失败:",B)}};u.useEffect(()=>{X(),k()},[f,p,v,S,M]);const se=async B=>{try{const W=await m1(B.person_id);O(W.data),H(!0)}catch(W){z({title:"加载详情失败",description:W instanceof Error?W.message:"无法加载人物详情",variant:"destructive"})}},_=B=>{O(B),V(!0)},ue=async B=>{try{await x1(B.person_id),z({title:"删除成功",description:`已删除人物信息: ${B.person_name||B.nickname||B.user_id}`}),T(null),X(),k()}catch(W){z({title:"删除失败",description:W instanceof Error?W.message:"无法删除人物信息",variant:"destructive"})}},ie=u.useMemo(()=>Object.keys(D.platforms),[D.platforms]),ae=B=>{const W=new Set(xe);W.has(B)?W.delete(B):W.add(B),_e(W)},fe=()=>{xe.size===n.length&&n.length>0?_e(new Set):_e(new Set(n.map(B=>B.person_id)))},Ne=()=>{if(xe.size===0){z({title:"未选择任何人物",description:"请先选择要删除的人物",variant:"destructive"});return}ge(!0)},me=async()=>{try{const B=await p1(Array.from(xe));z({title:"批量删除完成",description:B.message}),_e(new Set),ge(!1),X(),k()}catch(B){z({title:"批量删除失败",description:B instanceof Error?B.message:"批量删除失败",variant:"destructive"})}},G=()=>{const B=parseInt(ye),W=Math.ceil(h/p);B>=1&&B<=W?(j(B),be("")):z({title:"无效的页码",description:`请输入1-${W}之间的页码`,variant:"destructive"})},P=B=>B?new Date(B*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(Ou,{className:"h-8 w-8",strokeWidth:2}),"人物信息管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦认识的所有人物信息"})]})})}),e.jsx(ss,{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:D.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:D.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:D.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(b,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative mt-1.5",children:[e.jsx(zt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{id:"search",placeholder:"搜索名称、昵称或用户ID...",value:v,onChange:B=>y(B.target.value),className:"pl-9"})]})]}),e.jsxs("div",{children:[e.jsx(b,{htmlFor:"filter-known",children:"认识状态"}),e.jsxs(He,{value:S===void 0?"all":S.toString(),onValueChange:B=>{C(B==="all"?void 0:B==="true"),j(1)},children:[e.jsx(Le,{id:"filter-known",className:"mt-1.5",children:e.jsx(qe,{})}),e.jsxs(Ue,{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(b,{htmlFor:"filter-platform",children:"平台"}),e.jsxs(He,{value:M||"all",onValueChange:B=>{F(B==="all"?void 0:B),j(1)},children:[e.jsx(Le,{id:"filter-platform",className:"mt-1.5",children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"all",children:"全部平台"}),ie.map(B=>e.jsxs(le,{value:B,children:[B," (",D.platforms[B],")"]},B))]})]})]})]}),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:xe.size>0&&e.jsxs("span",{children:["已选择 ",xe.size," 个人物"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(He,{value:p.toString(),onValueChange:B=>{w(parseInt(B)),j(1),_e(new Set)},children:[e.jsx(Le,{id:"page-size",className:"w-20",children:e.jsx(qe,{})}),e.jsxs(Ue,{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"})]})]}),xe.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>_e(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:Ne,children:[e.jsx(ls,{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(hn,{children:[e.jsx(xn,{children:e.jsxs(ot,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:n.length>0&&xe.size===n.length,onCheckedChange:fe,"aria-label":"全选"})}),e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{children:"名称"}),e.jsx(Ie,{children:"昵称"}),e.jsx(Ie,{children:"平台"}),e.jsx(Ie,{children:"用户ID"}),e.jsx(Ie,{children:"最后更新"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c?e.jsx(ot,{children:e.jsx(Fe,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(ot,{children:e.jsx(Fe,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(B=>e.jsxs(ot,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:xe.has(B.person_id),onCheckedChange:()=>ae(B.person_id),"aria-label":`选择 ${B.person_name||B.nickname||B.user_id}`})}),e.jsx(Fe,{children:e.jsx("div",{className:$("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium",B.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:B.is_known?"已认识":"未认识"})}),e.jsx(Fe,{className:"font-medium",children:B.person_name||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Fe,{children:B.nickname||"-"}),e.jsx(Fe,{children:B.platform}),e.jsx(Fe,{className:"font-mono text-sm",children:B.user_id}),e.jsx(Fe,{className:"text-sm text-muted-foreground",children:P(B.last_know)}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>se(B),children:[e.jsx(Dt,{className:"h-4 w-4 mr-1"}),"详情"]}),e.jsxs(N,{variant:"default",size:"sm",onClick:()=>_(B),children:[e.jsx(mn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>T(B),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ls,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},B.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:c?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(B=>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:xe.has(B.person_id),onCheckedChange:()=>ae(B.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",B.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:B.is_known?"已认识":"未认识"}),e.jsx("h3",{className:"font-semibold text-sm line-clamp-1 w-full break-all",children:B.person_name||e.jsx("span",{className:"text-muted-foreground",children:"未命名"})}),B.nickname&&e.jsxs("p",{className:"text-xs text-muted-foreground mt-1 line-clamp-1 w-full break-all",children:["昵称: ",B.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:B.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:B.user_id,children:B.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:P(B.last_know)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>se(B),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(Dt,{className:"h-3 w-3 mr-1"}),"查看"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>_(B),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(mn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>T(B),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(ls,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},B.id))}),h>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:["共 ",h," 条记录,第 ",f," / ",Math.ceil(h/p)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(f-1),disabled:f===1,children:[e.jsx(Hl,{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(oe,{type:"number",value:ye,onChange:B=>be(B.target.value),onKeyDown:B=>B.key==="Enter"&&G(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(h/p)}),e.jsx(N,{variant:"outline",size:"sm",onClick:G,disabled:!ye,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(f+1),disabled:f>=Math.ceil(h/p),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(h/p)),disabled:f>=Math.ceil(h/p),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(j1,{person:U,open:K,onOpenChange:H}),e.jsx(v1,{person:U,open:A,onOpenChange:V,onSuccess:()=>{X(),k(),V(!1)}}),e.jsx(ps,{open:!!Q,onOpenChange:()=>T(null),children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认删除"}),e.jsxs(ds,{children:['确定要删除人物信息 "',Q?.person_name||Q?.nickname||Q?.user_id,'" 吗? 此操作不可撤销。']})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:()=>Q&&ue(Q),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(ps,{open:Se,onOpenChange:ge,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"确认批量删除"}),e.jsxs(ds,{children:["确定要删除选中的 ",xe.size," 个人物信息吗? 此操作不可撤销。"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{children:"取消"}),e.jsx(us,{onClick:me,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})})]})}function j1({person:n,open:i,onOpenChange:c}){if(!n)return null;const d=h=>h?new Date(h*1e3).toLocaleString("zh-CN"):"-";return e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"人物详情"}),e.jsxs(Is,{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(nl,{icon:Wc,label:"人物名称",value:n.person_name}),e.jsx(nl,{icon:un,label:"昵称",value:n.nickname}),e.jsx(nl,{icon:ri,label:"用户ID",value:n.user_id,mono:!0}),e.jsx(nl,{icon:ri,label:"人物ID",value:n.person_id,mono:!0}),e.jsx(nl,{label:"平台",value:n.platform}),e.jsx(nl,{label:"状态",value:n.is_known?"已认识":"未认识"})]}),n.name_reason&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(b,{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(b,{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(b,{className:"text-xs text-muted-foreground",children:"群昵称"}),e.jsx("div",{className:"mt-2 space-y-1",children:n.group_nick_name.map((h,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:h.group_id}),e.jsx("span",{children:"→"}),e.jsx("span",{children:h.group_nick_name})]},x))})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(nl,{icon:li,label:"认识时间",value:d(n.know_times)}),e.jsx(nl,{icon:li,label:"首次记录",value:d(n.know_since)}),e.jsx(nl,{icon:li,label:"最后更新",value:d(n.last_know)})]})]}),e.jsx(at,{children:e.jsx(N,{onClick:()=>c(!1),children:"关闭"})})]})})}function nl({icon:n,label:i,value:c,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(b,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:$("text-sm",d&&"font-mono",!c&&"text-muted-foreground"),children:c||"-"})]})}function v1({person:n,open:i,onOpenChange:c,onSuccess:d}){const[h,x]=u.useState({}),[f,j]=u.useState(!1),{toast:p}=Gs();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 w=async()=>{if(n)try{j(!0),await h1(n.person_id,h),p({title:"保存成功",description:"人物信息已更新"}),d()}catch(v){p({title:"保存失败",description:v instanceof Error?v.message:"无法更新人物信息",variant:"destructive"})}finally{j(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"编辑人物信息"}),e.jsxs(Is,{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(b,{htmlFor:"person_name",children:"人物名称"}),e.jsx(oe,{id:"person_name",value:h.person_name||"",onChange:v=>x({...h,person_name:v.target.value}),placeholder:"为这个人设置一个名称"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"nickname",children:"昵称"}),e.jsx(oe,{id:"nickname",value:h.nickname||"",onChange:v=>x({...h,nickname:v.target.value}),placeholder:"昵称"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"name_reason",children:"名称设定原因"}),e.jsx(Fs,{id:"name_reason",value:h.name_reason||"",onChange:v=>x({...h,name_reason:v.target.value}),placeholder:"为什么这样称呼这个人?",rows:2})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"memory_points",children:"个人印象"}),e.jsx(Fs,{id:"memory_points",value:h.memory_points||"",onChange:v=>x({...h,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(b,{htmlFor:"is_known",className:"text-base font-medium",children:"已认识"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"标记是否已经认识这个人"})]}),e.jsx(Xe,{id:"is_known",checked:h.is_known,onCheckedChange:v=>x({...h,is_known:v})})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:w,disabled:f,children:f?"保存中...":"保存"})]})]})}):null}var N1=uy();const hp=hN(N1),Iu="/api/webui";async function b1(n=100,i="all"){const c=`${Iu}/knowledge/graph?limit=${n}&node_type=${i}`,d=await fetch(c);if(!d.ok)throw new Error(`获取知识图谱失败: ${d.status}`);return d.json()}async function y1(){const n=await fetch(`${Iu}/knowledge/stats`);if(!n.ok)throw new Error("获取知识图谱统计信息失败");return n.json()}async function w1(n){const i=await fetch(`${Iu}/knowledge/search?query=${encodeURIComponent(n)}`);if(!i.ok)throw new Error("搜索知识节点失败");return i.json()}const Rg=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(eo,{type:"target",position:so.Top}),e.jsx("div",{className:"font-semibold text-white text-sm truncate max-w-[200px]",title:n.content,children:n.label}),e.jsx(eo,{type:"source",position:so.Bottom})]}));Rg.displayName="EntityNode";const Lg=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(eo,{type:"target",position:so.Top}),e.jsx("div",{className:"font-medium text-white text-xs truncate max-w-[150px]",title:n.content,children:n.label}),e.jsx(eo,{type:"source",position:so.Bottom})]}));Lg.displayName="ParagraphNode";const _1={entity:Rg,paragraph:Lg};function S1(n,i){const c=new hp.graphlib.Graph;c.setDefaultEdgeLabel(()=>({})),c.setGraph({rankdir:"TB",ranksep:100,nodesep:80});const d=[],h=[];return n.forEach(x=>{c.setNode(x.id,{width:150,height:50})}),i.forEach(x=>{c.setEdge(x.source,x.target)}),hp.layout(c),n.forEach(x=>{const f=c.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}})}),i.forEach((x,f)=>{const j={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&&(j.label=`${x.weight.toFixed(0)}`),h.push(j)}),{nodes:d,edges:h}}function C1(){const n=ga(),[i,c]=u.useState(!1),[d,h]=u.useState(null),[x,f]=u.useState(""),[j,p]=u.useState("all"),[w,v]=u.useState(50),[y,S]=u.useState("50"),[C,M]=u.useState(!1),[F,U]=u.useState(!0),[O,K]=u.useState(!1),[H,A]=u.useState(!1),[V,Q,T]=my([]),[D,ne,xe]=hy([]),[_e,Se]=u.useState(0),[ge,ye]=u.useState(null),[be,z]=u.useState(null),{toast:X}=Gs(),k=u.useCallback(me=>me.type==="entity"?"#6366f1":me.type==="paragraph"?"#10b981":"#6b7280",[]),se=u.useCallback(async(me=!1)=>{try{if(!me&&w>200){A(!0);return}c(!0);const[G,P]=await Promise.all([b1(w,j),y1()]);if(h(P),G.nodes.length===0){X({title:"提示",description:"知识库为空,请先导入知识数据"}),Q([]),ne([]);return}const{nodes:B,edges:W}=S1(G.nodes,G.edges);Q(B),ne(W),Se(B.length),P&&P.total_nodes>w&&X({title:"提示",description:`知识图谱包含 ${P.total_nodes} 个节点,当前显示 ${B.length} 个`}),X({title:"加载成功",description:`已加载 ${B.length} 个节点,${W.length} 条边`})}catch(G){console.error("加载知识图谱失败:",G),X({title:"加载失败",description:G instanceof Error?G.message:"未知错误",variant:"destructive"})}finally{c(!1)}},[w,j,X]),_=u.useCallback(async()=>{if(!x.trim()){X({title:"提示",description:"请输入搜索关键词"});return}try{const me=await w1(x);if(me.length===0){X({title:"未找到",description:"没有找到匹配的节点"});return}const G=new Set(me.map(P=>P.id));Q(P=>P.map(B=>({...B,style:{...B.style,opacity:G.has(B.id)?1:.3,filter:G.has(B.id)?"brightness(1.2)":"brightness(0.8)"}}))),X({title:"搜索完成",description:`找到 ${me.length} 个匹配节点`})}catch(me){console.error("搜索失败:",me),X({title:"搜索失败",description:me instanceof Error?me.message:"未知错误",variant:"destructive"})}},[x,X]),ue=u.useCallback(()=>{Q(me=>me.map(G=>({...G,style:{...G.style,opacity:1,filter:"brightness(1)"}})))},[]),ie=u.useCallback(()=>{U(!1),K(!0),se()},[se]),ae=u.useCallback(()=>{A(!1),setTimeout(()=>{se(!0)},0)},[se]),fe=u.useCallback((me,G)=>{V.find(B=>B.id===G.id)&&ye({id:G.id,type:G.type,content:G.data.content})},[V]);u.useEffect(()=>{F||O&&se()},[w,j,F,O]);const Ne=u.useCallback((me,G)=>{const P=V.find(Ce=>Ce.id===G.source),B=V.find(Ce=>Ce.id===G.target),W=D.find(Ce=>Ce.id===G.id);P&&B&&W&&z({source:{id:P.id,type:P.type,content:P.data.content},target:{id:B.id,type:B.type,content:B.data.content},edge:{source:G.source,target:G.target,weight:parseFloat(G.label||"0")}})},[V,D]);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(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(Ic,{className:"h-3 w-3"}),"节点: ",d.total_nodes]}),e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(ug,{className:"h-3 w-3"}),"边: ",d.total_edges]}),e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(Ra,{className:"h-3 w-3"}),"实体: ",d.entity_nodes]}),e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(Da,{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(oe,{placeholder:"搜索节点内容...",value:x,onChange:me=>f(me.target.value),onKeyDown:me=>me.key==="Enter"&&_(),className:"flex-1"}),e.jsx(N,{onClick:_,size:"sm",children:e.jsx(zt,{className:"h-4 w-4"})}),e.jsx(N,{onClick:ue,variant:"outline",size:"sm",children:"重置"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(He,{value:j,onValueChange:me=>p(me),children:[e.jsx(Le,{className:"w-[120px]",children:e.jsx(qe,{})}),e.jsxs(Ue,{children:[e.jsx(le,{value:"all",children:"全部节点"}),e.jsx(le,{value:"entity",children:"仅实体"}),e.jsx(le,{value:"paragraph",children:"仅段落"})]})]}),e.jsxs(He,{value:w===1e4?"all":C?"custom":w.toString(),onValueChange:me=>{me==="custom"?(M(!0),S(w.toString())):me==="all"?(M(!1),v(1e4)):(M(!1),v(Number(me)))},children:[e.jsx(Le,{className:"w-[120px]",children:e.jsx(qe,{})}),e.jsxs(Ue,{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:"自定义..."})]})]}),C&&e.jsx(oe,{type:"number",min:"50",value:y,onChange:me=>S(me.target.value),onBlur:()=>{const me=parseInt(y);!isNaN(me)&&me>=50?v(me):(S("50"),v(50))},onKeyDown:me=>{if(me.key==="Enter"){const G=parseInt(y);!isNaN(G)&&G>=50?v(G):(S("50"),v(50))}},placeholder:"最少50个",className:"w-[120px]"}),e.jsx(N,{onClick:()=>se(),variant:"outline",size:"sm",disabled:i,children:e.jsx(Ct,{className:$("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(Ct,{className:"h-8 w-8 animate-spin mx-auto mb-2 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"加载知识图谱中..."})]})}):V.length===0?e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(Ic,{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(xy,{nodes:V,edges:D,onNodesChange:T,onEdgesChange:xe,onNodeClick:fe,onEdgeClick:Ne,nodeTypes:_1,fitView:!0,minZoom:.05,maxZoom:1.5,defaultViewport:{x:0,y:0,zoom:.5},elevateNodesOnSelect:_e<=500,nodesDraggable:_e<=1e3,attributionPosition:"bottom-left",children:[e.jsx(fy,{variant:py.Dots,gap:12,size:1}),e.jsx(gy,{}),_e<=500&&e.jsx(jy,{nodeColor:k,nodeBorderRadius:8,pannable:!0,zoomable:!0}),e.jsxs(vy,{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:"段落节点"})]}),_e>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:"已禁用动画"}),_e>500&&e.jsx("div",{children:"已禁用缩略图"})]})]})]})]})}),e.jsx($s,{open:!!ge,onOpenChange:me=>!me&&ye(null),children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsx(Hs,{children:e.jsx(qs,{children:"节点详情"})}),ge&&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:ge.type==="entity"?"default":"secondary",children:ge.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:ge.id})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"内容"}),e.jsx(ss,{className:"mt-1 h-40 p-3 bg-muted rounded",children:e.jsx("p",{className:"text-sm whitespace-pre-wrap",children:ge.content})})]})]})]})}),e.jsx($s,{open:!!be,onOpenChange:me=>!me&&z(null),children:e.jsxs(Bs,{className:"max-w-2xl max-h-[80vh] overflow-hidden flex flex-col",children:[e.jsx(Hs,{children:e.jsx(qs,{children:"边详情"})}),be&&e.jsx(ss,{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(ps,{open:F,onOpenChange:U,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"加载知识图谱"}),e.jsxs(ds,{children:["知识图谱的动态展示会消耗较多系统资源。",e.jsx("br",{}),"确定要加载知识图谱吗?"]})]}),e.jsxs(cs,{children:[e.jsx(ms,{onClick:()=>n({to:"/"}),children:"取消 (返回首页)"}),e.jsx(us,{onClick:ie,children:"确认加载"})]})]})}),e.jsx(ps,{open:H,onOpenChange:A,children:e.jsxs(is,{children:[e.jsxs(rs,{children:[e.jsx(os,{children:"⚠️ 节点数量较多"}),e.jsx(ds,{asChild:!0,children:e.jsxs("div",{children:[e.jsxs("p",{children:["您正在尝试加载 ",e.jsx("strong",{className:"text-orange-600",children:w>=1e4?"全部 (最多10000个)":w})," 个节点。"]}),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(cs,{children:[e.jsx(ms,{onClick:()=>{A(!1),w>200&&(v(50),M(!1))},children:"取消"}),e.jsx(us,{onClick:ae,className:"bg-orange-600 hover:bg-orange-700",children:"我了解风险,继续加载"})]})]})})]})}function xp({className:n,classNames:i,showOutsideDays:c=!0,captionLayout:d="label",buttonVariant:h="ghost",formatters:x,components:f,...j}){const p=fg();return e.jsx(Xb,{showOutsideDays:c,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:w=>w.toLocaleString("default",{month:"short"}),...x},classNames:{root:$("w-fit",p.root),months:$("relative flex flex-col gap-4 md:flex-row",p.months),month:$("flex w-full flex-col gap-4",p.month),nav:$("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",p.nav),button_previous:$(gr({variant:h}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",p.button_previous),button_next:$(gr({variant:h}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",p.button_next),month_caption:$("flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]",p.month_caption),dropdowns:$("flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium",p.dropdowns),dropdown_root:$("has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",p.dropdown_root),dropdown:$("bg-popover absolute inset-0 opacity-0",p.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",p.caption_label),table:"w-full border-collapse",weekdays:$("flex",p.weekdays),weekday:$("text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal",p.weekday),week:$("mt-2 flex w-full",p.week),week_number_header:$("w-[--cell-size] select-none",p.week_number_header),week_number:$("text-muted-foreground select-none text-[0.8rem]",p.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",p.day),range_start:$("bg-accent rounded-l-md",p.range_start),range_middle:$("rounded-none",p.range_middle),range_end:$("bg-accent rounded-r-md",p.range_end),today:$("bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",p.today),outside:$("text-muted-foreground aria-selected:text-muted-foreground",p.outside),disabled:$("text-muted-foreground opacity-50",p.disabled),hidden:$("invisible",p.hidden),...i},components:{Root:({className:w,rootRef:v,...y})=>e.jsx("div",{"data-slot":"calendar",ref:v,className:$(w),...y}),Chevron:({className:w,orientation:v,...y})=>v==="left"?e.jsx(Hl,{className:$("size-4",w),...y}):v==="right"?e.jsx(ul,{className:$("size-4",w),...y}):e.jsx(Bl,{className:$("size-4",w),...y}),DayButton:k1,WeekNumber:({children:w,...v})=>e.jsx("td",{...v,children:e.jsx("div",{className:"flex size-[--cell-size] items-center justify-center text-center",children:w})}),...f},...j})}function k1({className:n,day:i,modifiers:c,...d}){const h=fg(),x=u.useRef(null);return u.useEffect(()=>{c.focused&&x.current?.focus()},[c.focused]),e.jsx(N,{ref:x,variant:"ghost",size:"icon","data-day":i.date.toLocaleDateString(),"data-selected-single":c.selected&&!c.range_start&&!c.range_end&&!c.range_middle,"data-range-start":c.range_start,"data-range-end":c.range_end,"data-range-middle":c.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",h.day,n),...d})}const T1={lessThanXSeconds:{one:"不到 1 秒",other:"不到 {{count}} 秒"},xSeconds:{one:"1 秒",other:"{{count}} 秒"},halfAMinute:"半分钟",lessThanXMinutes:{one:"不到 1 分钟",other:"不到 {{count}} 分钟"},xMinutes:{one:"1 分钟",other:"{{count}} 分钟"},xHours:{one:"1 小时",other:"{{count}} 小时"},aboutXHours:{one:"大约 1 小时",other:"大约 {{count}} 小时"},xDays:{one:"1 天",other:"{{count}} 天"},aboutXWeeks:{one:"大约 1 个星期",other:"大约 {{count}} 个星期"},xWeeks:{one:"1 个星期",other:"{{count}} 个星期"},aboutXMonths:{one:"大约 1 个月",other:"大约 {{count}} 个月"},xMonths:{one:"1 个月",other:"{{count}} 个月"},aboutXYears:{one:"大约 1 年",other:"大约 {{count}} 年"},xYears:{one:"1 年",other:"{{count}} 年"},overXYears:{one:"超过 1 年",other:"超过 {{count}} 年"},almostXYears:{one:"将近 1 年",other:"将近 {{count}} 年"}},E1=(n,i,c)=>{let d;const h=T1[n];return typeof h=="string"?d=h:i===1?d=h.one:d=h.other.replace("{{count}}",String(i)),c?.addSuffix?c.comparison&&c.comparison>0?d+"内":d+"前":d},z1={full:"y'年'M'月'd'日' EEEE",long:"y'年'M'月'd'日'",medium:"yyyy-MM-dd",short:"yy-MM-dd"},A1={full:"zzzz a h:mm:ss",long:"z a h:mm:ss",medium:"a h:mm:ss",short:"a h:mm"},M1={full:"{{date}} {{time}}",long:"{{date}} {{time}}",medium:"{{date}} {{time}}",short:"{{date}} {{time}}"},D1={date:vu({formats:z1,defaultWidth:"full"}),time:vu({formats:A1,defaultWidth:"full"}),dateTime:vu({formats:M1,defaultWidth:"full"})};function fp(n,i,c){const d="eeee p";return pN(n,i,c)?d:n.getTime()>i.getTime()?"'下个'"+d:"'上个'"+d}const O1={lastWeek:fp,yesterday:"'昨天' p",today:"'今天' p",tomorrow:"'明天' p",nextWeek:fp,other:"PP p"},R1=(n,i,c,d)=>{const h=O1[n];return typeof h=="function"?h(i,c,d):h},L1={narrow:["前","公元"],abbreviated:["前","公元"],wide:["公元前","公元"]},U1={narrow:["1","2","3","4"],abbreviated:["第一季","第二季","第三季","第四季"],wide:["第一季度","第二季度","第三季度","第四季度"]},B1={narrow:["一","二","三","四","五","六","七","八","九","十","十一","十二"],abbreviated:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],wide:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"]},H1={narrow:["日","一","二","三","四","五","六"],short:["日","一","二","三","四","五","六"],abbreviated:["周日","周一","周二","周三","周四","周五","周六"],wide:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]},q1={narrow:{am:"上",pm:"下",midnight:"凌晨",noon:"午",morning:"早",afternoon:"下午",evening:"晚",night:"夜"},abbreviated:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"},wide:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"}},G1={narrow:{am:"上",pm:"下",midnight:"凌晨",noon:"午",morning:"早",afternoon:"下午",evening:"晚",night:"夜"},abbreviated:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"},wide:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"}},V1=(n,i)=>{const c=Number(n);switch(i?.unit){case"date":return c.toString()+"日";case"hour":return c.toString()+"时";case"minute":return c.toString()+"分";case"second":return c.toString()+"秒";default:return"第 "+c.toString()}},F1={ordinalNumber:V1,era:tr({values:L1,defaultWidth:"wide"}),quarter:tr({values:U1,defaultWidth:"wide",argumentCallback:n=>n-1}),month:tr({values:B1,defaultWidth:"wide"}),day:tr({values:H1,defaultWidth:"wide"}),dayPeriod:tr({values:q1,defaultWidth:"wide",formattingValues:G1,defaultFormattingWidth:"wide"})},$1=/^(第\s*)?\d+(日|时|分|秒)?/i,Q1=/\d+/i,Y1={narrow:/^(前)/i,abbreviated:/^(前)/i,wide:/^(公元前|公元)/i},X1={any:[/^(前)/i,/^(公元)/i]},K1={narrow:/^[1234]/i,abbreviated:/^第[一二三四]刻/i,wide:/^第[一二三四]刻钟/i},J1={any:[/(1|一)/i,/(2|二)/i,/(3|三)/i,/(4|四)/i]},Z1={narrow:/^(一|二|三|四|五|六|七|八|九|十[二一])/i,abbreviated:/^(一|二|三|四|五|六|七|八|九|十[二一]|\d|1[12])月/i,wide:/^(一|二|三|四|五|六|七|八|九|十[二一])月/i},I1={narrow:[/^一/i,/^二/i,/^三/i,/^四/i,/^五/i,/^六/i,/^七/i,/^八/i,/^九/i,/^十(?!(一|二))/i,/^十一/i,/^十二/i],any:[/^一|1/i,/^二|2/i,/^三|3/i,/^四|4/i,/^五|5/i,/^六|6/i,/^七|7/i,/^八|8/i,/^九|9/i,/^十(?!(一|二))|10/i,/^十一|11/i,/^十二|12/i]},P1={narrow:/^[一二三四五六日]/i,short:/^[一二三四五六日]/i,abbreviated:/^周[一二三四五六日]/i,wide:/^星期[一二三四五六日]/i},W1={any:[/日/i,/一/i,/二/i,/三/i,/四/i,/五/i,/六/i]},e2={any:/^(上午?|下午?|午夜|[中正]午|早上?|下午|晚上?|凌晨|)/i},s2={any:{am:/^上午?/i,pm:/^下午?/i,midnight:/^午夜/i,noon:/^[中正]午/i,morning:/^早上/i,afternoon:/^下午/i,evening:/^晚上?/i,night:/^凌晨/i}},t2={ordinalNumber:gN({matchPattern:$1,parsePattern:Q1,valueCallback:n=>parseInt(n,10)}),era:ar({matchPatterns:Y1,defaultMatchWidth:"wide",parsePatterns:X1,defaultParseWidth:"any"}),quarter:ar({matchPatterns:K1,defaultMatchWidth:"wide",parsePatterns:J1,defaultParseWidth:"any",valueCallback:n=>n+1}),month:ar({matchPatterns:Z1,defaultMatchWidth:"wide",parsePatterns:I1,defaultParseWidth:"any"}),day:ar({matchPatterns:P1,defaultMatchWidth:"wide",parsePatterns:W1,defaultParseWidth:"any"}),dayPeriod:ar({matchPatterns:e2,defaultMatchWidth:"any",parsePatterns:s2,defaultParseWidth:"any"})},Vc={code:"zh-CN",formatDistance:E1,formatLong:D1,formatRelative:R1,localize:F1,match:t2,options:{weekStartsOn:1,firstWeekContainsDate:4}},Fc={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 a2(){const[n,i]=u.useState([]),[c,d]=u.useState(""),[h,x]=u.useState("all"),[f,j]=u.useState("all"),[p,w]=u.useState(void 0),[v,y]=u.useState(void 0),[S,C]=u.useState(!0),[M,F]=u.useState(!1),[U,O]=u.useState("xs"),[K,H]=u.useState(4),A=u.useRef(null);u.useEffect(()=>{const k=rn.getAllLogs();i(k);const se=rn.onLog(()=>{i(rn.getAllLogs())}),_=rn.onConnectionChange(ue=>{F(ue)});return()=>{se(),_()}},[]);const V=u.useMemo(()=>{const k=new Set(n.map(se=>se.module).filter(se=>se&&se.trim()!==""));return Array.from(k).sort()},[n]),Q=k=>{switch(k){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=k=>{switch(k){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"}},D=()=>{window.location.reload()},ne=()=>{rn.clearLogs(),i([])},xe=()=>{const k=ge.map(ie=>`${ie.timestamp} [${ie.level.padEnd(8)}] [${ie.module}] ${ie.message}`).join(` -`),se=new Blob([k],{type:"text/plain;charset=utf-8"}),_=URL.createObjectURL(se),ue=document.createElement("a");ue.href=_,ue.download=`logs-${Nu(new Date,"yyyy-MM-dd-HHmmss")}.txt`,ue.click(),URL.revokeObjectURL(_)},_e=()=>{C(!S)},Se=()=>{w(void 0),y(void 0)},ge=u.useMemo(()=>n.filter(k=>{const se=c===""||k.message.toLowerCase().includes(c.toLowerCase())||k.module.toLowerCase().includes(c.toLowerCase()),_=h==="all"||k.level===h,ue=f==="all"||k.module===f;let ie=!0;if(p||v){const ae=new Date(k.timestamp);if(p){const fe=new Date(p);fe.setHours(0,0,0,0),ie=ie&&ae>=fe}if(v){const fe=new Date(v);fe.setHours(23,59,59,999),ie=ie&&ae<=fe}}return se&&_&&ue&&ie}),[n,c,h,f,p,v]),ye=Fc[U].rowHeight+K,be=nN({count:ge.length,getScrollElement:()=>A.current,estimateSize:()=>ye,overscan:15}),z=u.useRef(!1),X=u.useRef(ge.length);return u.useEffect(()=>{const k=A.current;if(!k)return;const se=()=>{if(z.current)return;const{scrollTop:_,scrollHeight:ue,clientHeight:ie}=k,ae=ue-_-ie;ae>100&&S?C(!1):ae<50&&!S&&C(!0)};return k.addEventListener("scroll",se,{passive:!0}),()=>k.removeEventListener("scroll",se)},[S]),u.useEffect(()=>{const k=ge.length>X.current;X.current=ge.length,S&&ge.length>0&&k&&(z.current=!0,be.scrollToIndex(ge.length-1,{align:"end",behavior:"auto"}),requestAnimationFrame(()=>{requestAnimationFrame(()=>{z.current=!1})}))},[ge.length,S,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",M?"bg-green-500 animate-pulse":"bg-red-500")}),e.jsx("span",{className:"text-xs sm:text-sm text-muted-foreground",children:M?"已连接":"未连接"})]})]}),e.jsx(Ze,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{placeholder:"搜索日志...",value:c,onChange:k=>d(k.target.value),className:"pl-9 h-9 text-sm"})]}),e.jsxs(He,{value:h,onValueChange:x,children:[e.jsxs(Le,{className:"w-full sm:w-[140px] lg:w-[180px] h-9 text-sm",children:[e.jsx(Mu,{className:"h-4 w-4 mr-2"}),e.jsx(qe,{placeholder:"级别"})]}),e.jsxs(Ue,{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(He,{value:f,onValueChange:j,children:[e.jsxs(Le,{className:"w-full sm:w-[160px] lg:w-[200px] h-9 text-sm",children:[e.jsx(Mu,{className:"h-4 w-4 mr-2"}),e.jsx(qe,{placeholder:"模块"})]}),e.jsxs(Ue,{children:[e.jsx(le,{value:"all",children:"全部模块"}),V.map(k=>e.jsx(le,{value:k,children:k},k))]})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:gap-4",children:[e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:$("w-full sm:w-[200px] lg:w-[240px] justify-start text-left font-normal h-9",!p&&"text-muted-foreground"),children:[e.jsx(Qf,{className:"mr-2 h-4 w-4"}),e.jsx("span",{className:"text-xs sm:text-sm",children:p?Nu(p,"PPP",{locale:Vc}):"开始日期"})]})}),e.jsx(_a,{className:"w-auto p-0",align:"start",children:e.jsx(xp,{mode:"single",selected:p,onSelect:w,initialFocus:!0,locale:Vc})})]}),e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:$("w-full sm:w-[200px] lg:w-[240px] justify-start text-left font-normal h-9",!v&&"text-muted-foreground"),children:[e.jsx(Qf,{className:"mr-2 h-4 w-4"}),e.jsx("span",{className:"text-xs sm:text-sm",children:v?Nu(v,"PPP",{locale:Vc}):"结束日期"})]})}),e.jsx(_a,{className:"w-auto p-0",align:"start",children:e.jsx(xp,{mode:"single",selected:v,onSelect:y,initialFocus:!0,locale:Vc})})]}),(p||v)&&e.jsxs(N,{variant:"outline",size:"sm",onClick:Se,className:"w-full sm:w-auto h-9",children:[e.jsx(dl,{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(N,{variant:S?"default":"outline",size:"sm",onClick:_e,className:"flex-1 sm:flex-none h-9",children:[S?e.jsx(kb,{className:"h-4 w-4"}):e.jsx(Tb,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:S?"自动滚动":"已暂停"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:D,className:"flex-1 sm:flex-none h-9",children:[e.jsx(Ct,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"刷新"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:ne,className:"flex-1 sm:flex-none h-9",children:[e.jsx(ls,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"清空"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:xe,className:"flex-1 sm:flex-none h-9",children:[e.jsx(rl,{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:[ge.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(Eb,{className:"h-4 w-4"}),e.jsx("span",{children:"字号"})]}),e.jsx("div",{className:"flex gap-1",children:Object.keys(Fc).map(k=>e.jsx(N,{variant:U===k?"default":"outline",size:"sm",onClick:()=>O(k),className:"h-7 px-3 text-xs",children:Fc[k].label},k))})]}),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(Ma,{value:[K],onValueChange:([k])=>H(k),min:0,max:12,step:2,className:"flex-1"}),e.jsxs("span",{className:"text-xs text-muted-foreground w-8",children:[K,"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(Ze,{className:"bg-black dark:bg-gray-950 border-gray-800 dark:border-gray-900 h-full",children:e.jsx(ss,{viewportRef:A,className:"h-full",children:e.jsx("div",{className:$("p-2 sm:p-3 font-mono relative",Fc[U].class),style:{height:`${be.getTotalSize()}px`},children:ge.length===0?e.jsx("div",{className:"text-gray-500 dark:text-gray-600 text-center py-8 text-sm",children:"暂无日志数据"}):be.getVirtualItems().map(k=>{const se=ge[k.index];return e.jsxs("div",{"data-index":k.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(${k.start}px)`,paddingTop:`${K/2}px`,paddingBottom:`${K/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",Q(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",Q(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})]})]},k.key)})})})})})]})}const l2="Mai-with-u",n2="plugin-repo",i2="main",r2="plugin_details.json";async function c2(){try{const n=await Te("/api/webui/plugins/fetch-raw",{method:"POST",body:JSON.stringify({owner:l2,repo:n2,branch:i2,file_path:r2})});if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const i=await n.json();if(!i.success||!i.data)throw new Error(i.error||"获取插件列表失败");return JSON.parse(i.data).filter(h=>!h?.id||!h?.manifest?(console.warn("跳过无效插件数据:",h),!1):!h.manifest.name||!h.manifest.version?(console.warn("跳过缺少必需字段的插件:",h.id),!1):!0).map(h=>({id:h.id,manifest:{manifest_version:h.manifest.manifest_version||1,name:h.manifest.name,version:h.manifest.version,description:h.manifest.description||"",author:h.manifest.author||{name:"Unknown"},license:h.manifest.license||"Unknown",host_application:h.manifest.host_application||{min_version:"0.0.0"},homepage_url:h.manifest.homepage_url,repository_url:h.manifest.repository_url,keywords:h.manifest.keywords||[],categories:h.manifest.categories||[],default_locale:h.manifest.default_locale||"zh-CN",locales_path:h.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 o2(){try{const n=await Te("/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 d2(){try{const n=await Te("/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 u2(n,i,c){const d=n.split(".").map(j=>parseInt(j)||0),h=d[0]||0,x=d[1]||0,f=d[2]||0;if(c.version_majorparseInt(y)||0),p=j[0]||0,w=j[1]||0,v=j[2]||0;if(c.version_major>p||c.version_major===p&&c.version_minor>w||c.version_major===p&&c.version_minor===w&&c.version_patch>v)return!1}return!0}function m2(n,i){const c=window.location.protocol==="https:"?"wss:":"ws:",d=window.location.host,h=new WebSocket(`${c}//${d}/api/webui/ws/plugin-progress`);return h.onopen=()=>{console.log("Plugin progress WebSocket connected");const x=setInterval(()=>{h.readyState===WebSocket.OPEN?h.send("ping"):clearInterval(x)},3e4)},h.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)}},h.onerror=x=>{console.error("Plugin progress WebSocket error:",x),i?.(x)},h.onclose=()=>{console.log("Plugin progress WebSocket disconnected")},h}async function dr(){try{const n=await Te("/api/webui/plugins/installed",{headers:Ls()});if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const i=await n.json();if(!i.success)throw new Error(i.message||"获取已安装插件列表失败");return i.plugins||[]}catch(n){return console.error("Failed to get installed plugins:",n),[]}}function $c(n,i){return i.some(c=>c.id===n)}function Qc(n,i){const c=i.find(d=>d.id===n);if(c)return c.manifest?.version||c.version}async function h2(n,i,c="main"){const d=await Te("/api/webui/plugins/install",{method:"POST",body:JSON.stringify({plugin_id:n,repository_url:i,branch:c})});if(!d.ok){const h=await d.json();throw new Error(h.detail||"安装失败")}return await d.json()}async function x2(n){const i=await Te("/api/webui/plugins/uninstall",{method:"POST",body:JSON.stringify({plugin_id:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"卸载失败")}return await i.json()}async function f2(n,i,c="main"){const d=await Te("/api/webui/plugins/update",{method:"POST",body:JSON.stringify({plugin_id:n,repository_url:i,branch:c})});if(!d.ok){const h=await d.json();throw new Error(h.detail||"更新失败")}return await d.json()}async function p2(n){const i=await Te(`/api/webui/plugins/config/${n}/schema`,{headers:Ls()});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取配置 Schema 失败")}const c=await i.json();if(!c.success)throw new Error(c.message||"获取配置 Schema 失败");return c.schema}async function g2(n){const i=await Te(`/api/webui/plugins/config/${n}`,{headers:Ls()});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取配置失败")}const c=await i.json();if(!c.success)throw new Error(c.message||"获取配置失败");return c.config}async function j2(n,i){const c=await Te(`/api/webui/plugins/config/${n}`,{method:"PUT",body:JSON.stringify({config:i})});if(!c.ok){const d=await c.json();throw new Error(d.detail||"保存配置失败")}return await c.json()}async function v2(n){const i=await Te(`/api/webui/plugins/config/${n}/reset`,{method:"POST",headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"重置配置失败")}return await i.json()}async function N2(n){const i=await Te(`/api/webui/plugins/config/${n}/toggle`,{method:"POST",headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"切换状态失败")}return await i.json()}const _r="https://maibot-plugin-stats.maibot-webui.workers.dev";async function Ug(n){try{const i=await fetch(`${_r}/stats/${n}`);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 b2(n,i){try{const c=i||Pu(),d=await fetch(`${_r}/stats/like`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,user_id:c})}),h=await d.json();return d.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:d.ok?{success:!0,...h}:{success:!1,error:h.error||"点赞失败"}}catch(c){return console.error("Error liking plugin:",c),{success:!1,error:"网络错误"}}}async function y2(n,i){try{const c=i||Pu(),d=await fetch(`${_r}/stats/dislike`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,user_id:c})}),h=await d.json();return d.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:d.ok?{success:!0,...h}:{success:!1,error:h.error||"点踩失败"}}catch(c){return console.error("Error disliking plugin:",c),{success:!1,error:"网络错误"}}}async function w2(n,i,c,d){if(i<1||i>5)return{success:!1,error:"评分必须在 1-5 之间"};try{const h=d||Pu(),x=await fetch(`${_r}/stats/rate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,rating:i,comment:c,user_id:h})}),f=await x.json();return x.status===429?{success:!1,error:"每天最多评分 3 次"}:x.ok?{success:!0,...f}:{success:!1,error:f.error||"评分失败"}}catch(h){return console.error("Error rating plugin:",h),{success:!1,error:"网络错误"}}}async function _2(n){try{const i=await fetch(`${_r}/stats/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n})}),c=await i.json();return i.status===429?(console.warn("Download recording rate limited"),{success:!0}):i.ok?{success:!0,...c}:(console.error("Failed to record download:",c.error),{success:!1,error:c.error})}catch(i){return console.error("Error recording download:",i),{success:!1,error:"网络错误"}}}function S2(){const n=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,n.deviceMemory||0].join("|");let c=0;for(let d=0;d{x(!0);const O=await Ug(n);O&&d(O),x(!1)};u.useEffect(()=>{C()},[n]);const M=async()=>{const O=await b2(n);O.success?(S({title:"已点赞",description:"感谢你的支持!"}),C()):S({title:"点赞失败",description:O.error||"未知错误",variant:"destructive"})},F=async()=>{const O=await y2(n);O.success?(S({title:"已反馈",description:"感谢你的反馈!"}),C()):S({title:"操作失败",description:O.error||"未知错误",variant:"destructive"})},U=async()=>{if(f===0){S({title:"请选择评分",description:"至少选择 1 颗星",variant:"destructive"});return}const O=await w2(n,f,p||void 0);O.success?(S({title:"评分成功",description:"感谢你的评价!"}),y(!1),j(0),w(""),C()):S({title:"评分失败",description:O.error||"未知错误",variant:"destructive"})};return h?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(rl,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ul,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]})]}):c?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:`下载量: ${c.downloads.toLocaleString()}`,children:[e.jsx(rl,{className:"h-4 w-4"}),e.jsx("span",{children:c.downloads.toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`评分: ${c.rating.toFixed(1)} (${c.rating_count} 条评价)`,children:[e.jsx(Ul,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:c.rating.toFixed(1)})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`点赞数: ${c.likes}`,children:[e.jsx(yu,{className:"h-4 w-4"}),e.jsx("span",{children:c.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(rl,{className:"h-5 w-5 text-muted-foreground mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:c.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(Ul,{className:"h-5 w-5 text-yellow-400 mb-1 fill-yellow-400"}),e.jsx("span",{className:"text-2xl font-bold",children:c.rating.toFixed(1)}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[c.rating_count," 条评价"]})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(yu,{className:"h-5 w-5 text-green-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:c.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(Yf,{className:"h-5 w-5 text-red-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:c.dislikes}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"点踩"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:M,children:[e.jsx(yu,{className:"h-4 w-4 mr-1"}),"点赞"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:F,children:[e.jsx(Yf,{className:"h-4 w-4 mr-1"}),"点踩"]}),e.jsxs($s,{open:v,onOpenChange:y,children:[e.jsx(Xu,{asChild:!0,children:e.jsxs(N,{variant:"default",size:"sm",children:[e.jsx(Ul,{className:"h-4 w-4 mr-1"}),"评分"]})}),e.jsxs(Bs,{children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"为插件评分"}),e.jsx(Is,{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(O=>e.jsx("button",{onClick:()=>j(O),className:"focus:outline-none",children:e.jsx(Ul,{className:`h-8 w-8 transition-colors ${O<=f?"fill-yellow-400 text-yellow-400":"text-muted-foreground hover:text-yellow-300"}`})},O))}),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(Fs,{value:p,onChange:O=>w(O.target.value),placeholder:"分享你的使用体验...",rows:4,maxLength:500}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1 text-right",children:[p.length," / 500"]})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(N,{onClick:U,disabled:f===0,children:"提交评分"})]})]})]})]}),c.recent_ratings&&c.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:c.recent_ratings.map((O,K)=>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(H=>e.jsx(Ul,{className:`h-3 w-3 ${H<=O.rating?"fill-yellow-400 text-yellow-400":"text-muted-foreground"}`},H))}),e.jsx("span",{className:"text-xs text-muted-foreground",children:new Date(O.created_at).toLocaleDateString()})]}),O.comment&&e.jsx("p",{className:"text-sm text-muted-foreground",children:O.comment})]},K))})]})]}):null}const pp={"Group Management":"群组管理","Entertainment & Interaction":"娱乐互动","Utility Tools":"实用工具","Content Generation":"内容生成",Multimedia:"多媒体","External Integration":"外部集成","Data Analysis & Insights":"数据分析与洞察",Other:"其他"};function k2(){const n=ga(),[i,c]=u.useState(null),[d,h]=u.useState(""),[x,f]=u.useState("all"),[j,p]=u.useState("all"),[w,v]=u.useState(!0),[y,S]=u.useState([]),[C,M]=u.useState(!0),[F,U]=u.useState(null),[O,K]=u.useState(null),[H,A]=u.useState(null),[V,Q]=u.useState(null),[,T]=u.useState([]),[D,ne]=u.useState({}),{toast:xe}=Gs(),_e=async _=>{const ue=_.map(async fe=>{try{const Ne=await Ug(fe.id);return{id:fe.id,stats:Ne}}catch(Ne){return console.warn(`Failed to load stats for ${fe.id}:`,Ne),{id:fe.id,stats:null}}}),ie=await Promise.all(ue),ae={};ie.forEach(({id:fe,stats:Ne})=>{Ne&&(ae[fe]=Ne)}),ne(ae)};u.useEffect(()=>{let _=null,ue=!1;return(async()=>{if(_=m2(ae=>{ue||(A(ae),ae.stage==="success"?setTimeout(()=>{ue||A(null)},2e3):ae.stage==="error"&&(M(!1),U(ae.error||"加载失败")))},ae=>{console.error("WebSocket error:",ae),ue||xe({title:"WebSocket 连接失败",description:"无法实时显示加载进度",variant:"destructive"})}),await new Promise(ae=>{if(!_){ae();return}const fe=()=>{_&&_.readyState===WebSocket.OPEN?(console.log("WebSocket connected, starting to load plugins"),ae()):_&&_.readyState===WebSocket.CLOSED?(console.warn("WebSocket closed before loading plugins"),ae()):setTimeout(fe,100)};fe()}),!ue){const ae=await o2();K(ae),ae.installed||xe({title:"Git 未安装",description:ae.error||"请先安装 Git 才能使用插件安装功能",variant:"destructive"})}if(!ue){const ae=await d2();Q(ae)}if(!ue)try{M(!0),U(null);const ae=await c2();if(!ue){const fe=await dr();T(fe);const Ne=ae.map(me=>{const G=$c(me.id,fe),P=Qc(me.id,fe);return{...me,installed:G,installed_version:P}});for(const me of fe)!Ne.some(P=>P.id===me.id)&&me.manifest&&Ne.push({id:me.id,manifest:{manifest_version:me.manifest.manifest_version||1,name:me.manifest.name,version:me.manifest.version,description:me.manifest.description||"",author:me.manifest.author,license:me.manifest.license||"Unknown",host_application:me.manifest.host_application,homepage_url:me.manifest.homepage_url,repository_url:me.manifest.repository_url,keywords:me.manifest.keywords||[],categories:me.manifest.categories||[],default_locale:me.manifest.default_locale||"zh-CN",locales_path:me.manifest.locales_path},downloads:0,rating:0,review_count:0,installed:!0,installed_version:me.manifest.version,published_at:new Date().toISOString(),updated_at:new Date().toISOString()});S(Ne),_e(Ne)}}catch(ae){if(!ue){const fe=ae instanceof Error?ae.message:"加载插件列表失败";U(fe),xe({title:"加载失败",description:fe,variant:"destructive"})}}finally{ue||M(!1)}})(),()=>{ue=!0,_&&_.close()}},[xe]);const Se=_=>{if(!_.installed&&V&&!ge(_))return e.jsxs(Ye,{variant:"destructive",className:"gap-1",children:[e.jsx(Oa,{className:"h-3 w-3"}),"不兼容"]});if(_.installed){const ue=_.installed_version?.trim(),ie=_.manifest.version?.trim();if(ue!==ie){const ae=ue?.split(".").map(Number)||[0,0,0],fe=ie?.split(".").map(Number)||[0,0,0];for(let Ne=0;Ne<3;Ne++){if((fe[Ne]||0)>(ae[Ne]||0))return e.jsxs(Ye,{variant:"outline",className:"gap-1 text-orange-600 border-orange-600",children:[e.jsx(Oa,{className:"h-3 w-3"}),"可更新"]});if((fe[Ne]||0)<(ae[Ne]||0))break}}return e.jsxs(Ye,{variant:"default",className:"gap-1",children:[e.jsx(fa,{className:"h-3 w-3"}),"已安装"]})}return null},ge=_=>!V||!_.manifest?.host_application?!0:u2(_.manifest.host_application.min_version,_.manifest.host_application.max_version,V),ye=_=>{if(!_.installed||!_.installed_version||!_.manifest?.version)return!1;const ue=_.installed_version.trim(),ie=_.manifest.version.trim();if(ue===ie)return!1;const ae=ue.split(".").map(Number),fe=ie.split(".").map(Number);for(let Ne=0;Ne<3;Ne++){if((fe[Ne]||0)>(ae[Ne]||0))return!0;if((fe[Ne]||0)<(ae[Ne]||0))return!1}return!1},be=y.filter(_=>{if(!_.manifest)return console.warn("[过滤] 跳过无 manifest 的插件:",_.id),!1;const ue=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(Ne=>Ne.toLowerCase().includes(d.toLowerCase())),ie=x==="all"||_.manifest.categories&&_.manifest.categories.includes(x);let ae=!0;j==="installed"?ae=_.installed===!0:j==="updates"&&(ae=_.installed===!0&&ye(_));const fe=!w||!V||ge(_);return ue&&ie&&ae&&fe}),z=()=>{c(null)},X=async _=>{if(!O?.installed){xe({title:"无法安装",description:"Git 未安装",variant:"destructive"});return}if(V&&!ge(_)){xe({title:"无法安装",description:"插件与当前麦麦版本不兼容",variant:"destructive"});return}try{await h2(_.id,_.manifest.repository_url||"","main"),_2(_.id).catch(ie=>{console.warn("Failed to record download:",ie)}),xe({title:"安装成功",description:`${_.manifest.name} 已成功安装`});const ue=await dr();T(ue),S(ie=>ie.map(ae=>{if(ae.id===_.id){const fe=$c(ae.id,ue),Ne=Qc(ae.id,ue);return{...ae,installed:fe,installed_version:Ne}}return ae}))}catch(ue){xe({title:"安装失败",description:ue instanceof Error?ue.message:"未知错误",variant:"destructive"})}},k=async _=>{try{await x2(_.id),xe({title:"卸载成功",description:`${_.manifest.name} 已成功卸载`});const ue=await dr();T(ue),S(ie=>ie.map(ae=>{if(ae.id===_.id){const fe=$c(ae.id,ue),Ne=Qc(ae.id,ue);return{...ae,installed:fe,installed_version:Ne}}return ae}))}catch(ue){xe({title:"卸载失败",description:ue instanceof Error?ue.message:"未知错误",variant:"destructive"})}},se=async _=>{if(!O?.installed){xe({title:"无法更新",description:"Git 未安装",variant:"destructive"});return}try{const ue=await f2(_.id,_.manifest.repository_url||"","main");xe({title:"更新成功",description:`${_.manifest.name} 已从 ${ue.old_version} 更新到 ${ue.new_version}`});const ie=await dr();T(ie),S(ae=>ae.map(fe=>{if(fe.id===_.id){const Ne=$c(fe.id,ie),me=Qc(fe.id,ie);return{...fe,installed:Ne,installed_version:me}}return fe}))}catch(ue){xe({title:"更新失败",description:ue instanceof Error?ue.message:"未知错误",variant:"destructive"})}};return e.jsx(ss,{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(N,{onClick:()=>n({to:"/plugin-mirrors"}),children:[e.jsx(zb,{className:"h-4 w-4 mr-2"}),"配置镜像源"]})]}),O&&!O.installed&&e.jsxs(Ze,{className:"border-orange-600 bg-orange-50 dark:bg-orange-950/20",children:[e.jsx(ys,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(ya,{className:"h-5 w-5 text-orange-600"}),e.jsxs("div",{children:[e.jsx(ws,{className:"text-lg text-orange-900 dark:text-orange-100",children:"Git 未安装"}),e.jsx(ct,{className:"text-orange-800 dark:text-orange-200",children:O.error||"请先安装 Git 才能使用插件安装功能"})]})]})}),e.jsx(Ts,{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(Ze,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{placeholder:"搜索插件...",value:d,onChange:_=>h(_.target.value),className:"pl-9"})]}),e.jsxs(He,{value:x,onValueChange:f,children:[e.jsx(Le,{className:"w-full sm:w-[200px]",children:e.jsx(qe,{placeholder:"选择分类"})}),e.jsxs(Ue,{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(jt,{id:"compatible-only",checked:w,onCheckedChange:_=>v(_===!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(La,{value:j,onValueChange:p,className:"w-full",children:e.jsxs(wa,{className:"grid w-full grid-cols-3",children:[e.jsxs(fs,{value:"all",children:["全部插件 (",y.filter(_=>{if(!_.manifest)return!1;const ue=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(fe=>fe.toLowerCase().includes(d.toLowerCase())),ie=x==="all"||_.manifest.categories&&_.manifest.categories.includes(x),ae=!w||!V||ge(_);return ue&&ie&&ae}).length,")"]}),e.jsxs(fs,{value:"installed",children:["已安装 (",y.filter(_=>{if(!_.manifest)return!1;const ue=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(fe=>fe.toLowerCase().includes(d.toLowerCase())),ie=x==="all"||_.manifest.categories&&_.manifest.categories.includes(x),ae=!w||!V||ge(_);return _.installed&&ue&&ie&&ae}).length,")"]}),e.jsxs(fs,{value:"updates",children:["可更新 (",y.filter(_=>{if(!_.manifest)return!1;const ue=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(fe=>fe.toLowerCase().includes(d.toLowerCase())),ie=x==="all"||_.manifest.categories&&_.manifest.categories.includes(x),ae=!w||!V||ge(_);return _.installed&&ye(_)&&ue&&ie&&ae}).length,")"]})]})}),H&&H.stage==="loading"&&e.jsx(Ze,{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(kt,{className:"h-4 w-4 animate-spin"}),e.jsxs("span",{className:"text-sm font-medium",children:[H.operation==="fetch"&&"加载插件列表",H.operation==="install"&&`安装插件${H.plugin_id?`: ${H.plugin_id}`:""}`,H.operation==="uninstall"&&`卸载插件${H.plugin_id?`: ${H.plugin_id}`:""}`,H.operation==="update"&&`更新插件${H.plugin_id?`: ${H.plugin_id}`:""}`]})]}),e.jsxs("span",{className:"text-sm font-medium",children:[H.progress,"%"]})]}),e.jsx(wr,{value:H.progress,className:"h-2"}),e.jsx("div",{className:"text-xs text-muted-foreground",children:H.message}),H.operation==="fetch"&&H.total_plugins>0&&e.jsxs("div",{className:"text-xs text-muted-foreground text-center",children:["已加载 ",H.loaded_plugins," / ",H.total_plugins," 个插件"]})]})}),H&&H.stage==="error"&&H.error&&e.jsx(Ze,{className:"border-destructive bg-destructive/10",children:e.jsx(ys,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(ya,{className:"h-5 w-5 text-destructive"}),e.jsxs("div",{children:[e.jsx(ws,{className:"text-lg text-destructive",children:"加载失败"}),e.jsx(ct,{className:"text-destructive/80",children:H.error})]})]})})}),C?e.jsxs("div",{className:"flex items-center justify-center py-12",children:[e.jsx(kt,{className:"h-8 w-8 animate-spin text-muted-foreground"}),e.jsx("span",{className:"ml-3 text-muted-foreground",children:"加载插件列表中..."})]}):F?e.jsx(Ze,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(ya,{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(N,{onClick:()=>window.location.reload(),children:"重新加载"})]})}):be.length===0?e.jsx(Ze,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(zt,{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:be.map(_=>e.jsxs(Ze,{className:"flex flex-col hover:shadow-lg transition-shadow h-full",children:[e.jsxs(ys,{children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsx(ws,{className:"text-xl",children:_.manifest?.name||_.id}),e.jsxs("div",{className:"flex flex-col gap-1",children:[_.manifest?.categories&&_.manifest.categories[0]&&e.jsx(Ye,{variant:"secondary",className:"text-xs whitespace-nowrap",children:pp[_.manifest.categories[0]]||_.manifest.categories[0]}),Se(_)]})]}),e.jsx(ct,{className:"line-clamp-2",children:_.manifest?.description||"无描述"})]}),e.jsx(Ts,{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(rl,{className:"h-4 w-4"}),e.jsx("span",{children:(D[_.id]?.downloads??_.downloads??0).toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ul,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:(D[_.id]?.rating??_.rating??0).toFixed(1)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[_.manifest?.keywords&&_.manifest.keywords.slice(0,3).map(ue=>e.jsx(Ye,{variant:"outline",className:"text-xs",children:ue},ue)),_.manifest?.keywords&&_.manifest.keywords.length>3&&e.jsxs(Ye,{variant:"outline",className:"text-xs",children:["+",_.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",_.manifest?.version||"unknown"," · ",_.manifest?.author?.name||"Unknown"]}),_.manifest?.host_application&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{children:"支持:"}),e.jsxs("span",{className:"font-medium",children:[_.manifest.host_application.min_version,_.manifest.host_application.max_version?` - ${_.manifest.host_application.max_version}`:" - 最新版本"]})]})]})]})}),e.jsx(pg,{className:"pt-4",children:e.jsxs("div",{className:"flex items-center justify-end gap-2 w-full",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>c(_),children:"查看详情"}),_.installed?ye(_)?e.jsxs(N,{size:"sm",disabled:!O?.installed,title:O?.installed?void 0:"Git 未安装",onClick:()=>se(_),children:[e.jsx(Ct,{className:"h-4 w-4 mr-1"}),"更新"]}):e.jsxs(N,{variant:"destructive",size:"sm",disabled:!O?.installed,title:O?.installed?void 0:"Git 未安装",onClick:()=>k(_),children:[e.jsx(ls,{className:"h-4 w-4 mr-1"}),"卸载"]}):e.jsxs(N,{size:"sm",disabled:!O?.installed||H?.operation==="install"||V!==null&&!ge(_),title:O?.installed?V!==null&&!ge(_)?`不兼容当前版本 (需要 ${_.manifest?.host_application?.min_version||"未知"}${_.manifest?.host_application?.max_version?` - ${_.manifest.host_application.max_version}`:"+"},当前 ${V?.version})`:void 0:"Git 未安装",onClick:()=>X(_),children:[e.jsx(rl,{className:"h-4 w-4 mr-1"}),H?.operation==="install"&&H?.plugin_id===_.id?"安装中...":"安装"]})]})})]},_.id))}),e.jsx($s,{open:i!==null,onOpenChange:z,children:i&&i.manifest&&e.jsx(Bs,{className:"max-w-2xl max-h-[80vh] p-0 flex flex-col",children:e.jsx(ss,{className:"flex-1 overflow-auto",children:e.jsxs("div",{className:"p-6",children:[e.jsx(Hs,{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(qs,{className:"text-2xl",children:i.manifest.name}),e.jsxs(Is,{children:["作者: ",i.manifest.author?.name||"Unknown",i.manifest.author?.url&&e.jsx("a",{href:i.manifest.author.url,target:"_blank",rel:"noopener noreferrer",className:"ml-2 text-primary hover:underline",children:e.jsx(Xc,{className:"h-3 w-3 inline"})})]})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[i.manifest.categories&&i.manifest.categories[0]&&e.jsx(Ye,{variant:"secondary",children:pp[i.manifest.categories[0]]||i.manifest.categories[0]}),Se(i)]})]})}),e.jsxs("div",{className:"space-y-6",children:[e.jsx(C2,{pluginId:i.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",i.manifest?.version||"unknown"]}),i.installed&&i.installed_version&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["已安装: v",i.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:(D[i.id]?.downloads??i.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(Ul,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(D[i.id]?.rating??i.rating??0).toFixed(1)," (",D[i.id]?.rating_count??i.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:i.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:[i.manifest.host_application?.min_version||"未知",i.manifest.host_application?.max_version?` - ${i.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:i.manifest.keywords&&i.manifest.keywords.map(_=>e.jsx(Ye,{variant:"outline",children:_},_))})]}),i.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:i.detailed_description})]}),!i.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:i.manifest.description||"无描述"})]}),e.jsxs("div",{className:"space-y-2",children:[i.manifest.homepage_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"主页: "}),e.jsx("a",{href:i.manifest.homepage_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:i.manifest.homepage_url})]}),i.manifest.repository_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"仓库: "}),e.jsx("a",{href:i.manifest.repository_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:i.manifest.repository_url})]})]})]}),e.jsxs(at,{children:[i.manifest.homepage_url&&e.jsxs(N,{onClick:()=>window.open(i.manifest.homepage_url,"_blank"),children:[e.jsx(Xc,{className:"h-4 w-4 mr-2"}),"访问主页"]}),i.manifest.repository_url&&e.jsxs(N,{variant:"outline",onClick:()=>window.open(i.manifest.repository_url,"_blank"),children:[e.jsx(Xc,{className:"h-4 w-4 mr-2"}),"查看仓库"]})]})]})})})})]})})}const Bu=DN,Hu=ON,qu=RN;function T2({field:n,value:i,onChange:c}){const[d,h]=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(b,{children:n.label}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]}),e.jsx(Xe,{checked:!!i,onCheckedChange:c,disabled:n.disabled})]});case"number":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:n.label}),e.jsx(oe,{type:"number",value:i??n.default,onChange:x=>c(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(b,{children:n.label}),e.jsx("span",{className:"text-sm text-muted-foreground",children:i??n.default})]}),e.jsx(Ma,{value:[i??n.default],onValueChange:x=>c(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(b,{children:n.label}),e.jsxs(He,{value:String(i??n.default),onValueChange:c,disabled:n.disabled,children:[e.jsx(Le,{children:e.jsx(qe,{placeholder:n.placeholder??"请选择"})}),e.jsx(Ue,{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(b,{children:n.label}),e.jsx(Fs,{value:i??n.default,onChange:x=>c(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(b,{children:n.label}),e.jsxs("div",{className:"relative",children:[e.jsx(oe,{type:d?"text":"password",value:i??"",onChange:x=>c(x.target.value),placeholder:n.placeholder,disabled:n.disabled,className:"pr-10"}),e.jsx(N,{type:"button",variant:"ghost",size:"icon",className:"absolute right-0 top-0 h-full px-3",onClick:()=>h(!d),children:d?e.jsx(xr,{className:"h-4 w-4"}):e.jsx(Dt,{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(b,{children:n.label}),e.jsx(oe,{type:"text",value:i??n.default??"",onChange:x=>c(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 gp({section:n,config:i,onChange:c}){const[d,h]=u.useState(!n.collapsed),x=Object.entries(n.fields).filter(([,f])=>!f.hidden).sort(([,f],[,j])=>f.order-j.order);return e.jsx(Bu,{open:d,onOpenChange:h,children:e.jsxs(Ze,{children:[e.jsx(Hu,{asChild:!0,children:e.jsxs(ys,{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(Bl,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(ul,{className:"h-4 w-4 text-muted-foreground"}),e.jsx(ws,{className:"text-lg",children:n.title})]}),e.jsxs(Ye,{variant:"secondary",className:"text-xs",children:[x.length," 项"]})]}),n.description&&e.jsx(ct,{className:"ml-6",children:n.description})]})}),e.jsx(qu,{children:e.jsx(Ts,{className:"space-y-4 pt-0",children:x.map(([f,j])=>e.jsx(T2,{field:j,value:i[n.name]?.[f],onChange:p=>c(n.name,f,p),sectionName:n.name},f))})})]})})}function E2({plugin:n,onBack:i}){const{toast:c}=Gs(),[d,h]=u.useState(null),[x,f]=u.useState({}),[j,p]=u.useState({}),[w,v]=u.useState(!0),[y,S]=u.useState(!1),[C,M]=u.useState(!1),[F,U]=u.useState(!1),O=u.useCallback(async()=>{v(!0);try{const[D,ne]=await Promise.all([p2(n.id),g2(n.id)]);h(D),f(ne),p(JSON.parse(JSON.stringify(ne)))}catch(D){c({title:"加载配置失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}finally{v(!1)}},[n.id,c]);u.useEffect(()=>{O()},[O]),u.useEffect(()=>{M(JSON.stringify(x)!==JSON.stringify(j))},[x,j]);const K=(D,ne,xe)=>{f(_e=>({..._e,[D]:{..._e[D]||{},[ne]:xe}}))},H=async()=>{S(!0);try{await j2(n.id,x),p(JSON.parse(JSON.stringify(x))),c({title:"配置已保存",description:"更改将在插件重新加载后生效"})}catch(D){c({title:"保存失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}finally{S(!1)}},A=async()=>{try{await v2(n.id),c({title:"配置已重置",description:"下次加载插件时将使用默认配置"}),U(!1),O()}catch(D){c({title:"重置失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}},V=async()=>{try{const D=await N2(n.id);c({title:D.message,description:D.note}),O()}catch(D){c({title:"切换状态失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}};if(w)return e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx(kt,{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(Oa,{className:"h-12 w-12 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"无法加载配置"}),e.jsxs(N,{onClick:i,variant:"outline",children:[e.jsx(ii,{className:"h-4 w-4 mr-2"}),"返回"]})]});const Q=Object.values(d.sections).sort((D,ne)=>D.order-ne.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(N,{variant:"ghost",size:"icon",onClick:i,children:e.jsx(ii,{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(Ye,{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(N,{variant:"outline",size:"sm",onClick:V,children:[e.jsx(br,{className:"h-4 w-4 mr-2"}),T?"禁用":"启用"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>U(!0),children:[e.jsx(Zc,{className:"h-4 w-4 mr-2"}),"重置"]}),e.jsxs(N,{size:"sm",onClick:H,disabled:!C||y,children:[y?e.jsx(kt,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(yr,{className:"h-4 w-4 mr-2"}),"保存"]})]})]}),C&&e.jsx(Ze,{className:"border-orange-200 bg-orange-50 dark:bg-orange-950/20 dark:border-orange-900",children:e.jsx(Ts,{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(La,{defaultValue:d.layout.tabs[0]?.id,children:[e.jsx(wa,{children:d.layout.tabs.map(D=>e.jsxs(fs,{value:D.id,children:[D.title,D.badge&&e.jsx(Ye,{variant:"secondary",className:"ml-2 text-xs",children:D.badge})]},D.id))}),d.layout.tabs.map(D=>e.jsx(Ms,{value:D.id,className:"space-y-4 mt-4",children:D.sections.map(ne=>{const xe=d.sections[ne];return xe?e.jsx(gp,{section:xe,config:x,onChange:K},ne):null})},D.id))]}):e.jsx("div",{className:"space-y-4",children:Q.map(D=>e.jsx(gp,{section:D,config:x,onChange:K},D.name))}),e.jsx($s,{open:F,onOpenChange:U,children:e.jsxs(Bs,{children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"确认重置配置"}),e.jsx(Is,{children:"这将删除当前配置文件,下次加载插件时将使用默认配置。此操作不可撤销。"})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>U(!1),children:"取消"}),e.jsx(N,{variant:"destructive",onClick:A,children:"确认重置"})]})]})})]})}function z2(){const{toast:n}=Gs(),[i,c]=u.useState([]),[d,h]=u.useState(!0),[x,f]=u.useState(""),[j,p]=u.useState(null),w=async()=>{h(!0);try{const C=await dr();c(C)}catch(C){n({title:"加载插件列表失败",description:C instanceof Error?C.message:"未知错误",variant:"destructive"})}finally{h(!1)}};u.useEffect(()=>{w()},[]);const v=i.filter(C=>{const M=x.toLowerCase();return C.id.toLowerCase().includes(M)||C.manifest.name.toLowerCase().includes(M)||C.manifest.description?.toLowerCase().includes(M)}),y=i.length,S=0;return j?e.jsx(ss,{className:"h-full",children:e.jsx("div",{className:"p-4 sm:p-6",children:e.jsx(E2,{plugin:j,onBack:()=>p(null)})})}):e.jsx(ss,{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(N,{variant:"outline",size:"sm",onClick:w,children:[e.jsx(Ct,{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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"已安装插件"}),e.jsx(dn,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-2xl font-bold",children:i.length}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:d?"正在加载...":"个插件"})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"已启用"}),e.jsx(fa,{className:"h-4 w-4 text-green-600"})]}),e.jsxs(Ts,{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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"已禁用"}),e.jsx(Oa,{className:"h-4 w-4 text-orange-600"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-2xl font-bold",children:S}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"未激活的插件"})]})]})]}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{placeholder:"搜索插件...",value:x,onChange:C=>f(C.target.value),className:"pl-9"})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"已安装的插件"}),e.jsx(ct,{children:"点击插件查看和编辑配置"})]}),e.jsx(Ts,{children:d?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx(kt,{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(dn,{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(C=>e.jsxs("div",{className:"flex items-center justify-between p-4 rounded-lg border hover:bg-muted/50 cursor-pointer transition-colors",onClick:()=>p(C),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(dn,{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:C.manifest.name}),e.jsxs(Ye,{variant:"secondary",className:"text-xs flex-shrink-0",children:["v",C.manifest.version]})]}),e.jsx("p",{className:"text-sm text-muted-foreground truncate",children:C.manifest.description||"暂无描述"})]})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-shrink-0",children:[e.jsx(N,{variant:"ghost",size:"sm",children:e.jsx(oi,{className:"h-4 w-4"})}),e.jsx(ul,{className:"h-4 w-4 text-muted-foreground"})]})]},C.id))})})]})]})})}function A2(){const n=ga(),{toast:i}=Gs(),[c,d]=u.useState([]),[h,x]=u.useState(!0),[f,j]=u.useState(null),[p,w]=u.useState(null),[v,y]=u.useState(!1),[S,C]=u.useState(!1),[M,F]=u.useState({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),U=u.useCallback(async()=>{try{x(!0),j(null);const T=localStorage.getItem("access-token"),D=await fetch("/api/webui/plugins/mirrors",{headers:{Authorization:`Bearer ${T}`}});if(!D.ok)throw new Error("获取镜像源列表失败");const ne=await D.json();d(ne.mirrors||[])}catch(T){const D=T instanceof Error?T.message:"加载镜像源失败";j(D),i({title:"加载失败",description:D,variant:"destructive"})}finally{x(!1)}},[i]);u.useEffect(()=>{U()},[U]);const O=async()=>{try{const T=localStorage.getItem("access-token"),D=await fetch("/api/webui/plugins/mirrors",{method:"POST",headers:{Authorization:`Bearer ${T}`,"Content-Type":"application/json"},body:JSON.stringify(M)});if(!D.ok){const ne=await D.json();throw new Error(ne.detail||"添加镜像源失败")}i({title:"添加成功",description:"镜像源已添加"}),y(!1),F({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),U()}catch(T){i({title:"添加失败",description:T instanceof Error?T.message:"未知错误",variant:"destructive"})}},K=async()=>{if(p)try{const T=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${p.id}`,{method:"PUT",headers:{Authorization:`Bearer ${T}`,"Content-Type":"application/json"},body:JSON.stringify({name:M.name,raw_prefix:M.raw_prefix,clone_prefix:M.clone_prefix,enabled:M.enabled,priority:M.priority})})).ok)throw new Error("更新镜像源失败");i({title:"更新成功",description:"镜像源已更新"}),C(!1),w(null),U()}catch(T){i({title:"更新失败",description:T instanceof Error?T.message:"未知错误",variant:"destructive"})}},H=async T=>{if(confirm("确定要删除这个镜像源吗?"))try{const D=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T}`,{method:"DELETE",headers:{Authorization:`Bearer ${D}`}})).ok)throw new Error("删除镜像源失败");i({title:"删除成功",description:"镜像源已删除"}),U()}catch(D){i({title:"删除失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}},A=async T=>{try{const D=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T.id}`,{method:"PUT",headers:{Authorization:`Bearer ${D}`,"Content-Type":"application/json"},body:JSON.stringify({enabled:!T.enabled})})).ok)throw new Error("更新状态失败");U()}catch(D){i({title:"更新失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}},V=T=>{w(T),F({id:T.id,name:T.name,raw_prefix:T.raw_prefix,clone_prefix:T.clone_prefix,enabled:T.enabled,priority:T.priority}),C(!0)},Q=async(T,D)=>{const ne=D==="up"?T.priority-1:T.priority+1;if(!(ne<1))try{const xe=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T.id}`,{method:"PUT",headers:{Authorization:`Bearer ${xe}`,"Content-Type":"application/json"},body:JSON.stringify({priority:ne})})).ok)throw new Error("更新优先级失败");U()}catch(xe){i({title:"更新失败",description:xe instanceof Error?xe.message:"未知错误",variant:"destructive"})}};return e.jsx(ss,{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(N,{variant:"ghost",size:"icon",onClick:()=>n({to:"/plugins"}),children:e.jsx(ii,{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(N,{onClick:()=>y(!0),children:[e.jsx(xt,{className:"h-4 w-4 mr-2"}),"添加镜像源"]})]}),h?e.jsx(Ze,{className:"p-6",children:e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(kt,{className:"h-8 w-8 animate-spin text-primary"})})}):f?e.jsx(Ze,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(ya,{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(N,{onClick:U,children:"重新加载"})]})}):e.jsxs(Ze,{children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(hn,{children:[e.jsx(xn,{children:e.jsxs(ot,{children:[e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{children:"名称"}),e.jsx(Ie,{children:"ID"}),e.jsx(Ie,{children:"优先级"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c.map(T=>e.jsxs(ot,{children:[e.jsx(Fe,{children:e.jsx(Xe,{checked:T.enabled,onCheckedChange:()=>A(T)})}),e.jsx(Fe,{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(Fe,{children:e.jsx(Ye,{variant:"outline",children:T.id})}),e.jsx(Fe,{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(N,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>Q(T,"up"),disabled:T.priority===1,children:e.jsx(pr,{className:"h-3 w-3"})}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>Q(T,"down"),children:e.jsx(Bl,{className:"h-3 w-3"})})]})]})}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(N,{variant:"ghost",size:"icon",onClick:()=>V(T),children:e.jsx(on,{className:"h-4 w-4"})}),e.jsx(N,{variant:"ghost",size:"icon",onClick:()=>H(T.id),children:e.jsx(ls,{className:"h-4 w-4 text-destructive"})})]})})]},T.id))})]})}),e.jsx("div",{className:"md:hidden p-4 space-y-4",children:c.map(T=>e.jsx(Ze,{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(Ye,{variant:"default",className:"text-xs",children:"启用"})]}),e.jsx(Ye,{variant:"outline",className:"mt-1 text-xs",children:T.id})]}),e.jsx(Xe,{checked:T.enabled,onCheckedChange:()=>A(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(N,{variant:"outline",size:"sm",className:"flex-1",onClick:()=>V(T),children:[e.jsx(on,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>Q(T,"up"),disabled:T.priority===1,children:e.jsx(pr,{className:"h-4 w-4"})}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>Q(T,"down"),children:e.jsx(Bl,{className:"h-4 w-4"})}),e.jsx(N,{variant:"destructive",size:"sm",onClick:()=>H(T.id),children:e.jsx(ls,{className:"h-4 w-4"})})]})]})},T.id))})]}),e.jsx($s,{open:v,onOpenChange:y,children:e.jsxs(Bs,{className:"max-w-lg",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"添加镜像源"}),e.jsx(Is,{children:"添加新的 Git 镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-id",children:"镜像源 ID *"}),e.jsx(oe,{id:"add-id",placeholder:"例如: my-mirror",value:M.id,onChange:T=>F({...M,id:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-name",children:"名称 *"}),e.jsx(oe,{id:"add-name",placeholder:"例如: 我的镜像源",value:M.name,onChange:T=>F({...M,name:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-raw",children:"Raw 文件前缀 *"}),e.jsx(oe,{id:"add-raw",placeholder:"https://example.com/raw",value:M.raw_prefix,onChange:T=>F({...M,raw_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-clone",children:"克隆前缀 *"}),e.jsx(oe,{id:"add-clone",placeholder:"https://example.com/clone",value:M.clone_prefix,onChange:T=>F({...M,clone_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-priority",children:"优先级"}),e.jsx(oe,{id:"add-priority",type:"number",min:"1",value:M.priority,onChange:T=>F({...M,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(Xe,{id:"add-enabled",checked:M.enabled,onCheckedChange:T=>F({...M,enabled:T})}),e.jsx(b,{htmlFor:"add-enabled",children:"启用此镜像源"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(N,{onClick:O,children:"添加"})]})]})}),e.jsx($s,{open:S,onOpenChange:C,children:e.jsxs(Bs,{className:"max-w-lg",children:[e.jsxs(Hs,{children:[e.jsx(qs,{children:"编辑镜像源"}),e.jsx(Is,{children:"修改镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"镜像源 ID"}),e.jsx(oe,{value:M.id,disabled:!0})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-name",children:"名称 *"}),e.jsx(oe,{id:"edit-name",value:M.name,onChange:T=>F({...M,name:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-raw",children:"Raw 文件前缀 *"}),e.jsx(oe,{id:"edit-raw",value:M.raw_prefix,onChange:T=>F({...M,raw_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-clone",children:"克隆前缀 *"}),e.jsx(oe,{id:"edit-clone",value:M.clone_prefix,onChange:T=>F({...M,clone_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-priority",children:"优先级"}),e.jsx(oe,{id:"edit-priority",type:"number",min:"1",value:M.priority,onChange:T=>F({...M,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(Xe,{id:"edit-enabled",checked:M.enabled,onCheckedChange:T=>F({...M,enabled:T})}),e.jsx(b,{htmlFor:"edit-enabled",children:"启用此镜像源"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>C(!1),children:"取消"}),e.jsx(N,{onClick:K,children:"保存"})]})]})})]})})}const ur=u.forwardRef(({className:n,...i},c)=>e.jsx(Lp,{ref:c,className:$("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",n),...i}));ur.displayName=Lp.displayName;const M2=u.forwardRef(({className:n,...i},c)=>e.jsx(Up,{ref:c,className:$("aspect-square h-full w-full",n),...i}));M2.displayName=Up.displayName;const mr=u.forwardRef(({className:n,...i},c)=>e.jsx(Bp,{ref:c,className:$("flex h-full w-full items-center justify-center rounded-full bg-muted",n),...i}));mr.displayName=Bp.displayName;function D2(){return"webui_"+Math.random().toString(36).substr(2,9)+"_"+Date.now().toString(36)}function O2(){const n="maibot_webui_user_id";let i=localStorage.getItem(n);return i||(i=D2(),localStorage.setItem(n,i)),i}function R2(){return localStorage.getItem("maibot_webui_user_name")||"WebUI用户"}function L2(n){localStorage.setItem("maibot_webui_user_name",n)}const Bg="maibot_webui_virtual_tabs";function U2(){try{const n=localStorage.getItem(Bg);if(n)return JSON.parse(n)}catch(n){console.error("[Chat] 加载虚拟标签页失败:",n)}return[]}function jp(n){try{localStorage.setItem(Bg,JSON.stringify(n))}catch(i){console.error("[Chat] 保存虚拟标签页失败:",i)}}function B2(){const n={id:"webui-default",type:"webui",label:"WebUI",messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}},i=()=>{const Re=U2().map(ze=>{const $e=ze.virtualConfig;return!$e.groupId&&$e.platform&&$e.userId&&($e.groupId=`webui_virtual_group_${$e.platform}_${$e.userId}`),{id:ze.id,type:"virtual",label:ze.label,virtualConfig:$e,messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}}});return[n,...Re]},[c,d]=u.useState(i),[h,x]=u.useState("webui-default"),f=c.find(R=>R.id===h)||c[0],[j,p]=u.useState(""),[w,v]=u.useState(!1),[y,S]=u.useState(!0),[C,M]=u.useState(R2()),[F,U]=u.useState(!1),[O,K]=u.useState(""),[H,A]=u.useState(!1),[V,Q]=u.useState([]),[T,D]=u.useState([]),[ne,xe]=u.useState(!1),[_e,Se]=u.useState(!1),[ge,ye]=u.useState(""),[be,z]=u.useState({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),X=u.useRef(O2()),k=u.useRef(new Map),se=u.useRef(null),_=u.useRef(new Map),ue=u.useRef(0),ie=u.useRef(new Map),{toast:ae}=Gs(),fe=R=>(ue.current+=1,`${R}-${Date.now()}-${ue.current}-${Math.random().toString(36).substr(2,9)}`),Ne=u.useCallback((R,Re)=>{d(ze=>ze.map($e=>$e.id===R?{...$e,...Re}:$e))},[]),me=u.useCallback((R,Re)=>{d(ze=>ze.map($e=>$e.id===R?{...$e,messages:[...$e.messages,Re]}:$e))},[]),G=u.useCallback(()=>{se.current?.scrollIntoView({behavior:"smooth"})},[]);u.useEffect(()=>{G()},[f?.messages,G]);const P=u.useCallback(async()=>{xe(!0);try{const R=await Te("/api/chat/platforms");if(console.log("[Chat] 平台列表响应:",R.status,R.headers.get("content-type")),R.ok){const Re=R.headers.get("content-type");if(Re&&Re.includes("application/json")){const ze=await R.json();console.log("[Chat] 平台列表数据:",ze),Q(ze.platforms||[])}else{const ze=await R.text();console.error("[Chat] 获取平台列表失败: 非 JSON 响应:",ze.substring(0,200)),ae({title:"连接失败",description:"无法连接到后端服务,请确保 MaiBot 已启动",variant:"destructive"})}}else console.error("[Chat] 获取平台列表失败: HTTP",R.status),ae({title:"获取平台失败",description:`服务器返回错误: ${R.status}`,variant:"destructive"})}catch(R){console.error("[Chat] 获取平台列表失败:",R),ae({title:"网络错误",description:"无法连接到后端服务",variant:"destructive"})}finally{xe(!1)}},[ae]),B=u.useCallback(async(R,Re)=>{Se(!0);try{const ze=new URLSearchParams;R&&ze.append("platform",R),Re&&ze.append("search",Re),ze.append("limit","50");const $e=await Te(`/api/chat/persons?${ze.toString()}`);if($e.ok){const Es=$e.headers.get("content-type");if(Es&&Es.includes("application/json")){const We=await $e.json();D(We.persons||[])}else console.error("[Chat] 获取用户列表失败: 后端返回非 JSON 响应")}}catch(ze){console.error("[Chat] 获取用户列表失败:",ze)}finally{Se(!1)}},[]);u.useEffect(()=>{be.platform&&B(be.platform,ge)},[be.platform,ge,B]);const W=u.useCallback(async(R,Re)=>{S(!0);try{const ze=new URLSearchParams;ze.append("user_id",X.current),ze.append("limit","50"),Re&&ze.append("group_id",Re);const $e=`/api/chat/history?${ze.toString()}`;console.log("[Chat] 正在加载历史消息:",$e);const Es=await Te($e);if(Es.ok){const We=await Es.text();try{const nt=JSON.parse(We);if(nt.messages&&nt.messages.length>0){const vs=nt.messages.map(ve=>({id:ve.id,type:ve.type,content:ve.content,timestamp:ve.timestamp,sender:{name:ve.sender_name||(ve.is_bot?"麦麦":"WebUI用户"),user_id:ve.user_id,is_bot:ve.is_bot}}));Ne(R,{messages:vs});const ke=ie.current.get(R)||new Set;vs.forEach(ve=>{if(ve.type==="bot"){const ns=`bot-${ve.content}-${Math.floor(ve.timestamp*1e3)}`;ke.add(ns)}}),ie.current.set(R,ke)}}catch(nt){console.error("[Chat] JSON 解析失败:",nt)}}}catch(ze){console.error("[Chat] 加载历史消息失败:",ze)}finally{S(!1)}},[Ne]),Ce=u.useCallback((R,Re,ze)=>{const $e=k.current.get(R);if($e?.readyState===WebSocket.OPEN||$e?.readyState===WebSocket.CONNECTING){console.log(`[Tab ${R}] WebSocket 已存在,跳过连接`);return}v(!0);const Es=window.location.protocol==="https:"?"wss:":"ws:",We=new URLSearchParams;Re==="virtual"&&ze?(We.append("user_id",ze.userId),We.append("user_name",ze.userName),We.append("platform",ze.platform),We.append("person_id",ze.personId),We.append("group_name",ze.groupName||"WebUI虚拟群聊"),ze.groupId&&We.append("group_id",ze.groupId)):(We.append("user_id",X.current),We.append("user_name",C));const nt=`${Es}//${window.location.host}/api/chat/ws?${We.toString()}`;console.log(`[Tab ${R}] 正在连接 WebSocket:`,nt);try{const vs=new WebSocket(nt);k.current.set(R,vs),vs.onopen=()=>{Ne(R,{isConnected:!0}),v(!1),console.log(`[Tab ${R}] WebSocket 已连接`)},vs.onmessage=ke=>{try{const ve=JSON.parse(ke.data);switch(ve.type){case"session_info":Ne(R,{sessionInfo:{session_id:ve.session_id,user_id:ve.user_id,user_name:ve.user_name,bot_name:ve.bot_name}});break;case"system":me(R,{id:fe("sys"),type:"system",content:ve.content||"",timestamp:ve.timestamp||Date.now()/1e3});break;case"user_message":{const ns=ve.sender?.user_id,_s=Re==="virtual"&&ze?ze.userId:X.current;if(ns===_s)break;me(R,{id:ve.message_id||fe("user"),type:"user",content:ve.content||"",timestamp:ve.timestamp||Date.now()/1e3,sender:ve.sender});break}case"bot_message":{Ne(R,{isTyping:!1});const ns=ie.current.get(R)||new Set,_s=`bot-${ve.content}-${Math.floor((ve.timestamp||0)*1e3)}`;if(ns.has(_s))break;if(ns.add(_s),ie.current.set(R,ns),ns.size>100){const At=ns.values().next().value;At&&ns.delete(At)}d(At=>At.map(Ps=>{if(Ps.id!==R)return Ps;const Ys=Ps.messages.filter(Et=>Et.type!=="thinking");return{...Ps,messages:[...Ys,{id:fe("bot"),type:"bot",content:ve.content||"",timestamp:ve.timestamp||Date.now()/1e3,sender:ve.sender}]}}));break}case"typing":Ne(R,{isTyping:ve.is_typing||!1});break;case"error":d(ns=>ns.map(_s=>{if(_s.id!==R)return _s;const At=_s.messages.filter(Ps=>Ps.type!=="thinking");return{..._s,messages:[...At,{id:fe("error"),type:"error",content:ve.content||"发生错误",timestamp:ve.timestamp||Date.now()/1e3}]}})),ae({title:"错误",description:ve.content,variant:"destructive"});break;case"pong":break;case"history":{const ns=ve.messages||[];if(ns.length>0){const _s=ie.current.get(R)||new Set,At=ns.map(Ps=>{const Ys=Ps.is_bot||!1,Et=Ps.id||fe(Ys?"bot":"user"),Rt=`${Ys?"bot":"user"}-${Ps.content}-${Math.floor(Ps.timestamp*1e3)}`;return _s.add(Rt),{id:Et,type:Ys?"bot":"user",content:Ps.content,timestamp:Ps.timestamp,sender:{name:Ps.sender_name||(Ys?"麦麦":"用户"),user_id:Ps.sender_id,is_bot:Ys}}});ie.current.set(R,_s),Ne(R,{messages:At}),console.log(`[Tab ${R}] 已加载 ${At.length} 条历史消息`)}break}default:console.log("未知消息类型:",ve.type)}}catch(ve){console.error("解析消息失败:",ve)}},vs.onclose=()=>{Ne(R,{isConnected:!1}),v(!1),k.current.delete(R),console.log(`[Tab ${R}] WebSocket 已断开`);const ke=_.current.get(R);ke&&clearTimeout(ke);const ve=window.setTimeout(()=>{if(!Me.current){const ns=c.find(_s=>_s.id===R);ns&&Ce(R,ns.type,ns.virtualConfig)}},5e3);_.current.set(R,ve)},vs.onerror=ke=>{console.error(`[Tab ${R}] WebSocket 错误:`,ke),v(!1)}}catch(vs){console.error(`[Tab ${R}] 创建 WebSocket 失败:`,vs),v(!1)}},[C,Ne,me,ae,c]),Me=u.useRef(!1);u.useEffect(()=>{Me.current=!1;const R=k.current,Re=_.current,ze=ie.current;W("webui-default");const $e=setTimeout(()=>{Me.current||(Ce("webui-default","webui"),c.forEach(We=>{We.type==="virtual"&&We.virtualConfig&&(ze.set(We.id,new Set),setTimeout(()=>{Me.current||Ce(We.id,"virtual",We.virtualConfig)},200))}))},100),Es=setInterval(()=>{R.forEach(We=>{We.readyState===WebSocket.OPEN&&We.send(JSON.stringify({type:"ping"}))})},3e4);return()=>{Me.current=!0,clearTimeout($e),clearInterval(Es),Re.forEach(We=>{clearTimeout(We)}),Re.clear(),R.forEach(We=>{We.close()}),R.clear()}},[]);const re=u.useCallback(()=>{const R=k.current.get(h);if(!j.trim()||!R||R.readyState!==WebSocket.OPEN)return;const Re=f?.type==="virtual"&&f.virtualConfig?.userName||C,ze=j.trim(),$e=Date.now()/1e3;R.send(JSON.stringify({type:"message",content:ze,user_name:Re}));const Es={id:fe("user"),type:"user",content:ze,timestamp:$e,sender:{name:Re,is_bot:!1}};me(h,Es);const We={id:fe("thinking"),type:"thinking",content:"",timestamp:$e+.001,sender:{name:f?.sessionInfo.bot_name||"麦麦",is_bot:!0}};me(h,We),p("")},[j,C,h,f,me]),De=R=>{R.key==="Enter"&&!R.shiftKey&&(R.preventDefault(),re())},Vs=()=>{K(C),U(!0)},Qs=()=>{const R=O.trim()||"WebUI用户";M(R),L2(R),U(!1);const Re=k.current.get(h);Re?.readyState===WebSocket.OPEN&&Re.send(JSON.stringify({type:"update_nickname",user_name:R}))},de=()=>{K(""),U(!1)},Ee=R=>new Date(R*1e3).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"}),ts=()=>{const R=k.current.get(h);R&&(R.close(),k.current.delete(h)),Ce(h,f?.type||"webui",f?.virtualConfig)},Ke=()=>{z({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),ye(""),P(),A(!0)},lt=()=>{if(!be.platform||!be.personId){ae({title:"配置不完整",description:"请选择平台和用户",variant:"destructive"});return}const R=`webui_virtual_group_${be.platform}_${be.userId}`,Re=`virtual-${be.platform}-${be.userId}-${Date.now()}`,ze=be.userName||be.userId,$e={id:Re,type:"virtual",label:ze,virtualConfig:{...be,groupId:R},messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}};d(Es=>{const We=[...Es,$e],nt=We.filter(vs=>vs.type==="virtual"&&vs.virtualConfig).map(vs=>({id:vs.id,label:vs.label,virtualConfig:vs.virtualConfig,createdAt:Date.now()}));return jp(nt),We}),x(Re),A(!1),ie.current.set(Re,new Set),setTimeout(()=>{Ce(Re,"virtual",be)},100),ae({title:"虚拟身份标签页",description:`已创建 ${ze} 的对话`})},Ot=(R,Re)=>{if(Re?.stopPropagation(),R==="webui-default")return;const ze=k.current.get(R);ze&&(ze.close(),k.current.delete(R));const $e=_.current.get(R);$e&&(clearTimeout($e),_.current.delete(R)),ie.current.delete(R),d(Es=>{const We=Es.filter(vs=>vs.id!==R),nt=We.filter(vs=>vs.type==="virtual"&&vs.virtualConfig).map(vs=>({id:vs.id,label:vs.label,virtualConfig:vs.virtualConfig,createdAt:Date.now()}));return jp(nt),We}),h===R&&x("webui-default")},bt=R=>{x(R)},Pe=R=>{z(Re=>({...Re,personId:R.person_id,userId:R.user_id,userName:R.nickname||R.person_name}))};return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsx($s,{open:H,onOpenChange:A,children:e.jsxs(Bs,{className:"sm:max-w-[500px] max-h-[85vh] overflow-hidden flex flex-col",children:[e.jsxs(Hs,{children:[e.jsxs(qs,{className:"flex items-center gap-2",children:[e.jsx(wu,{className:"h-5 w-5"}),"新建虚拟身份对话"]}),e.jsx(Is,{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(b,{className:"flex items-center gap-2",children:[e.jsx(Du,{className:"h-4 w-4"}),"选择平台"]}),e.jsxs(He,{value:be.platform,onValueChange:R=>{z(Re=>({...Re,platform:R,personId:"",userId:"",userName:""})),D([])},children:[e.jsx(Le,{disabled:ne,children:e.jsx(qe,{placeholder:ne?"加载中...":"选择平台"})}),e.jsx(Ue,{children:V.map(R=>e.jsxs(le,{value:R.platform,children:[R.platform," (",R.count," 人)"]},R.platform))})]})]}),be.platform&&e.jsxs("div",{className:"space-y-2 flex-1 overflow-hidden flex flex-col",children:[e.jsxs(b,{className:"flex items-center gap-2",children:[e.jsx(Ou,{className:"h-4 w-4"}),"选择用户"]}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(oe,{placeholder:"搜索用户名...",value:ge,onChange:R=>ye(R.target.value),className:"pl-9"})]}),e.jsx(ss,{className:"h-[250px] border rounded-md",children:e.jsx("div",{className:"p-2",children:_e?e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(kt,{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(Ou,{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(R=>e.jsxs("button",{onClick:()=>Pe(R),className:$("w-full flex items-center gap-3 p-2 rounded-md text-left transition-colors",be.personId===R.person_id?"bg-primary text-primary-foreground":"hover:bg-muted"),children:[e.jsx(ur,{className:"h-8 w-8 shrink-0",children:e.jsx(mr,{className:$("text-xs",be.personId===R.person_id?"bg-primary-foreground/20":"bg-muted"),children:(R.nickname||R.person_name||"?").charAt(0)})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-medium truncate",children:R.nickname||R.person_name}),e.jsxs("div",{className:$("text-xs truncate",be.personId===R.person_id?"text-primary-foreground/70":"text-muted-foreground"),children:["ID: ",R.user_id,R.is_known&&" · 已认识"]})]})]},R.person_id))})})})]}),be.personId&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"虚拟群名(可选)"}),e.jsx(oe,{placeholder:"WebUI虚拟群聊",value:be.groupName,onChange:R=>z(Re=>({...Re,groupName:R.target.value}))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦会认为这是一个名为此名称的群聊"})]})]}),e.jsxs(at,{className:"gap-2 sm:gap-0",children:[e.jsx(N,{variant:"outline",onClick:()=>A(!1),children:"取消"}),e.jsx(N,{onClick:lt,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:[c.map(R=>e.jsxs("button",{onClick:()=>bt(R.id),className:$("flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm whitespace-nowrap transition-colors","hover:bg-muted",h===R.id?"bg-background shadow-sm border":"text-muted-foreground"),children:[R.type==="webui"?e.jsx(un,{className:"h-3.5 w-3.5"}):e.jsx(wu,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"max-w-[100px] truncate",children:R.label}),e.jsx("span",{className:$("w-1.5 h-1.5 rounded-full",R.isConnected?"bg-green-500":"bg-muted-foreground/50")}),R.id!=="webui-default"&&e.jsx("button",{onClick:Re=>Ot(R.id,Re),className:"ml-0.5 p-0.5 rounded hover:bg-muted-foreground/20",children:e.jsx(dl,{className:"h-3 w-3"})})]},R.id)),e.jsx("button",{onClick:Ke,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(xt,{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(ur,{className:"h-8 w-8 sm:h-10 sm:w-10 shrink-0",children:e.jsx(mr,{className:"bg-primary/10 text-primary",children:e.jsx(cr,{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(Ab,{className:"h-3 w-3 text-green-500"}),e.jsx("span",{className:"text-green-600 dark:text-green-400",children:"已连接"})]}):w?e.jsxs(e.Fragment,{children:[e.jsx(kt,{className:"h-3 w-3 animate-spin"}),e.jsx("span",{children:"连接中..."})]}):e.jsxs(e.Fragment,{children:[e.jsx(Mb,{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(kt,{className:"h-4 w-4 animate-spin text-muted-foreground"}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-8 w-8",onClick:ts,disabled:w,title:"重新连接",children:e.jsx(Ct,{className:$("h-4 w-4",w&&"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(wu,{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(Wc,{className:"h-3 w-3"}),e.jsx("span",{children:"当前身份:"}),F?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(oe,{value:O,onChange:R=>K(R.target.value),onKeyDown:R=>{R.key==="Enter"&&Qs(),R.key==="Escape"&&de()},className:"h-7 w-32",placeholder:"输入昵称",autoFocus:!0}),e.jsx(N,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:Qs,children:"保存"}),e.jsx(N,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:de,children:"取消"})]}):e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"font-medium text-foreground",children:C}),e.jsx(N,{size:"sm",variant:"ghost",className:"h-6 w-6 p-0",onClick:Vs,title:"修改昵称",children:e.jsx(Db,{className:"h-3 w-3"})})]})]})})]})}),e.jsx("div",{className:"flex-1 overflow-hidden",children:e.jsx(ss,{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(cr,{className:"h-12 w-12 mb-4 opacity-50"}),e.jsxs("p",{className:"text-sm",children:["开始与 ",f?.sessionInfo.bot_name||"麦麦"," 对话吧!"]})]}),f?.messages.map(R=>e.jsxs("div",{className:$("flex gap-2 sm:gap-3",R.type==="user"&&"flex-row-reverse",R.type==="system"&&"justify-center",R.type==="error"&&"justify-center"),children:[R.type==="system"&&e.jsx("div",{className:"text-xs text-muted-foreground bg-muted/50 px-3 py-1 rounded-full max-w-[90%]",children:R.content}),R.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:R.content}),R.type==="thinking"&&e.jsxs(e.Fragment,{children:[e.jsx(ur,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(mr,{className:"bg-primary/10 text-primary",children:e.jsx(cr,{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:R.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:"思考中..."})]})})]})]}),(R.type==="user"||R.type==="bot")&&e.jsxs(e.Fragment,{children:[e.jsx(ur,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(mr,{className:$("text-xs",R.type==="bot"?"bg-primary/10 text-primary":"bg-secondary text-secondary-foreground"),children:R.type==="bot"?e.jsx(cr,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"}):e.jsx(Wc,{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%]",R.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:R.sender?.name||(R.type==="bot"?f?.sessionInfo.bot_name:C)}),e.jsx("span",{children:Ee(R.timestamp)})]}),e.jsx("div",{className:$("rounded-2xl px-3 py-2 text-sm whitespace-pre-wrap break-words",R.type==="bot"?"bg-muted rounded-tl-sm":"bg-primary text-primary-foreground rounded-tr-sm"),children:R.content})]})]})]},R.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(oe,{value:j,onChange:R=>p(R.target.value),onKeyDown:De,placeholder:f?.isConnected?"输入消息...":"等待连接...",disabled:!f?.isConnected,className:"flex-1 h-10 sm:h-10"}),e.jsx(N,{onClick:re,disabled:!f?.isConnected||!j.trim(),size:"icon",className:"h-10 w-10 shrink-0",children:e.jsx(Ob,{className:"h-4 w-4"})})]})})})]})}function H2(){const n=ga(),[i,c]=u.useState(!0);return u.useEffect(()=>{let d=!1;return(async()=>{try{const x=await Ku();!d&&!x&&n({to:"/auth"})}catch{d||n({to:"/auth"})}finally{d||c(!1)}})(),()=>{d=!0}},[n]),{checking:i}}async function q2(){return await Ku()}const G2=ci("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"}}),Hg=u.forwardRef(({className:n,size:i,abbrTitle:c,children:d,...h},x)=>e.jsx("kbd",{className:$(G2({size:i,className:n})),ref:x,...h,children:c?e.jsx("abbr",{title:c,children:d}):d}));Hg.displayName="Kbd";const V2=[{icon:ao,title:"首页",description:"查看仪表板概览",path:"/",category:"概览"},{icon:Da,title:"麦麦主程序配置",description:"配置麦麦的核心设置",path:"/config/bot",category:"配置"},{icon:mg,title:"麦麦模型提供商配置",description:"配置模型提供商",path:"/config/modelProvider",category:"配置"},{icon:hg,title:"麦麦模型配置",description:"配置模型参数",path:"/config/model",category:"配置"},{icon:Gu,title:"表情包管理",description:"管理麦麦的表情包",path:"/resource/emoji",category:"资源"},{icon:un,title:"表达方式管理",description:"管理麦麦的表达方式",path:"/resource/expression",category:"资源"},{icon:xg,title:"人物信息管理",description:"管理人物信息",path:"/resource/person",category:"资源"},{icon:ri,title:"黑话管理",description:"管理麦麦学习到的黑话和俚语",path:"/resource/jargon",category:"资源"},{icon:Rb,title:"统计信息",description:"查看使用统计",path:"/statistics",category:"监控"},{icon:dn,title:"插件市场",description:"浏览和安装插件",path:"/plugins",category:"扩展"},{icon:Vu,title:"日志查看器",description:"查看系统日志",path:"/logs",category:"监控"},{icon:oi,title:"系统设置",description:"配置系统参数",path:"/settings",category:"系统"}];function F2({open:n,onOpenChange:i}){const[c,d]=u.useState(""),[h,x]=u.useState(0),f=ga(),j=V2.filter(v=>v.title.toLowerCase().includes(c.toLowerCase())||v.description.toLowerCase().includes(c.toLowerCase())||v.category.toLowerCase().includes(c.toLowerCase()));u.useEffect(()=>{n&&(d(""),x(0))},[n]);const p=u.useCallback(v=>{f({to:v}),i(!1)},[f,i]),w=u.useCallback(v=>{v.key==="ArrowDown"?(v.preventDefault(),x(y=>(y+1)%j.length)):v.key==="ArrowUp"?(v.preventDefault(),x(y=>(y-1+j.length)%j.length)):v.key==="Enter"&&j[h]&&(v.preventDefault(),p(j[h].path))},[j,h,p]);return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Bs,{className:"max-w-2xl p-0 gap-0",children:[e.jsxs(Hs,{className:"px-4 pt-4 pb-0",children:[e.jsx(qs,{className:"sr-only",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground"}),e.jsx(oe,{value:c,onChange:v=>{d(v.target.value),x(0)},onKeyDown:w,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(ss,{className:"h-[400px]",children:j.length>0?e.jsx("div",{className:"p-2",children:j.map((v,y)=>{const S=v.icon;return e.jsxs("button",{onClick:()=>p(v.path),onMouseEnter:()=>x(y),className:$("w-full flex items-center gap-3 px-3 py-2.5 rounded-md text-left transition-colors",y===h?"bg-accent text-accent-foreground":"hover:bg-accent/50"),children:[e.jsx(S,{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(zt,{className:"h-12 w-12 text-muted-foreground/50 mb-4"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:c?"未找到匹配的页面":"输入关键词开始搜索"})]})})}),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 $2=lb,Q2=nb,Y2=ib,qg=u.forwardRef(({className:n,sideOffset:i=4,...c},d)=>e.jsx(ab,{children:e.jsx(Pp,{ref:d,sideOffset:i,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),...c})}));qg.displayName=Pp.displayName;function X2({children:n}){const{checking:i}=H2(),[c,d]=u.useState(!0),[h,x]=u.useState(!1),[f,j]=u.useState(!1),{theme:p,setTheme:w}=$u(),v=iN();if(u.useEffect(()=>{const F=U=>{(U.metaKey||U.ctrlKey)&&U.key==="k"&&(U.preventDefault(),j(!0))};return window.addEventListener("keydown",F),()=>window.removeEventListener("keydown",F)},[]),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:ao,label:"首页",path:"/"}]},{title:"麦麦配置编辑",items:[{icon:Da,label:"麦麦主程序配置",path:"/config/bot"},{icon:mg,label:"AI模型厂商配置",path:"/config/modelProvider",tourId:"sidebar-model-provider"},{icon:hg,label:"模型管理与分配",path:"/config/model",tourId:"sidebar-model-management"},{icon:Xf,label:"麦麦适配器配置",path:"/config/adapter"}]},{title:"麦麦资源管理",items:[{icon:Gu,label:"表情包管理",path:"/resource/emoji"},{icon:un,label:"表达方式管理",path:"/resource/expression"},{icon:ri,label:"黑话管理",path:"/resource/jargon"},{icon:xg,label:"人物信息管理",path:"/resource/person"},{icon:ug,label:"知识库图谱可视化",path:"/resource/knowledge-graph"}]},{title:"扩展与监控",items:[{icon:dn,label:"插件市场",path:"/plugins"},{icon:Xf,label:"插件配置",path:"/plugin-config"},{icon:Vu,label:"日志查看器",path:"/logs"},{icon:un,label:"本地聊天室",path:"/chat"}]},{title:"系统",items:[{icon:oi,label:"系统设置",path:"/settings"}]}],C=p==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":p,M=async()=>{await l0()};return e.jsx($2,{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",c?"lg:w-64":"lg:w-16",h?"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",!c&&"lg:flex-none lg:w-8"),children:[e.jsxs("div",{className:$("flex items-baseline gap-2",!c&&"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:Vy()})]}),!c&&e.jsx("span",{className:"hidden lg:block font-bold text-primary-gradient text-2xl",children:"M"})]})}),e.jsx(ss,{className:$("flex-1 overflow-x-hidden",!c&&"lg:w-16"),children:e.jsx("nav",{className:$("p-4",!c&&"lg:p-2 lg:w-16"),children:e.jsx("ul",{className:$("space-y-6",!c&&"lg:space-y-3 lg:w-full"),children:y.map((F,U)=>e.jsxs("li",{children:[e.jsx("div",{className:$("px-3 h-[1.25rem]","mb-2",!c&&"lg:mb-1 lg:invisible"),children:e.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-muted-foreground/60 whitespace-nowrap",children:F.title})}),!c&&U>0&&e.jsx("div",{className:"hidden lg:block mb-2 border-t border-border"}),e.jsx("ul",{className:"space-y-1",children:F.items.map(O=>{const K=v({to:O.path}),H=O.icon,A=e.jsxs(e.Fragment,{children:[K&&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",c?"gap-3":"gap-3 lg:gap-0"),children:[e.jsx(H,{className:$("h-5 w-5 flex-shrink-0",K&&"text-primary"),strokeWidth:2,fill:"none"}),e.jsx("span",{className:$("text-sm font-medium whitespace-nowrap transition-all duration-300",K&&"font-semibold",c?"opacity-100 max-w-[200px]":"opacity-100 max-w-[200px] lg:opacity-0 lg:max-w-0 lg:overflow-hidden"),children:O.label})]})]});return e.jsx("li",{className:"relative",children:e.jsxs(Q2,{children:[e.jsx(Y2,{asChild:!0,children:e.jsx(Yc,{to:O.path,"data-tour":O.tourId,className:$("relative flex items-center rounded-lg py-2 transition-all duration-300","hover:bg-accent hover:text-accent-foreground",K?"bg-accent text-foreground":"text-muted-foreground hover:text-foreground",c?"px-3":"px-3 lg:px-0 lg:justify-center lg:w-12 lg:mx-auto"),onClick:()=>x(!1),children:A})}),!c&&e.jsx(qg,{side:"right",className:"hidden lg:block",children:e.jsx("p",{children:O.label})})]})},O.path)})})]},F.title))})})})]}),h&&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(!h),className:"rounded-lg p-2 hover:bg-accent lg:hidden",children:e.jsx(Lb,{className:"h-5 w-5"})}),e.jsx("button",{onClick:()=>d(!c),className:"hidden rounded-lg p-2 hover:bg-accent lg:block",title:c?"收起侧边栏":"展开侧边栏",children:e.jsx(Hl,{className:$("h-5 w-5 transition-transform",!c&&"rotate-180")})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>j(!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(zt,{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(Hg,{size:"sm",className:"absolute right-2 top-1/2 -translate-y-1/2",children:[e.jsx("span",{className:"text-xs",children:"⌘"}),"K"]})]}),e.jsx(F2,{open:f,onOpenChange:j}),e.jsxs(N,{variant:"ghost",size:"sm",onClick:()=>window.open("https://docs.mai-mai.org","_blank"),className:"gap-2",title:"查看麦麦文档",children:[e.jsx(Ub,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"麦麦文档"})]}),e.jsx("button",{onClick:F=>{Uy(C==="dark"?"light":"dark",w,F)},className:"rounded-lg p-2 hover:bg-accent",title:C==="dark"?"切换到浅色模式":"切换到深色模式",children:C==="dark"?e.jsx(ig,{className:"h-5 w-5"}):e.jsx(rg,{className:"h-5 w-5"})}),e.jsx("div",{className:"h-6 w-px bg-border"}),e.jsxs(N,{variant:"ghost",size:"sm",onClick:M,className:"gap-2",title:"登出系统",children:[e.jsx(Bb,{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 K2(n){const i=n.split(` -`).slice(1),c=[];for(const d of i){const h=d.trim();if(!h.startsWith("at "))continue;const x=h.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/);x?c.push({functionName:x[1]||"",fileName:x[2],lineNumber:x[3],columnNumber:x[4],raw:h}):c.push({functionName:"",fileName:"",lineNumber:"",columnNumber:"",raw:h})}return c}function J2({error:n,errorInfo:i}){const[c,d]=u.useState(!0),[h,x]=u.useState(!1),[f,j]=u.useState(!1),p=n.stack?K2(n.stack):[],w=async()=>{const v=` + `,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:M.previewUrl,alt:M.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:M.name}),e.jsx("p",{className:"text-xs text-muted-foreground truncate",children:M.emotion||"未填写情感标签"})]}),ne?e.jsx(fa,{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"})]},M.id)})})}),e.jsx("div",{className:"border rounded-lg p-4",children:L?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:L.previewUrl,alt:L.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:L.name}),O(L)&&e.jsxs($e,{variant:"outline",className:"text-green-600 border-green-600",children:[e.jsx($t,{className:"h-3 w-3 mr-1"}),"已完成"]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"multi-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"multi-emotion",value:L.emotion,onChange:M=>k(L.id,{emotion:M.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:L.emotion.trim()?"":"border-destructive"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"multi-description",children:"描述"}),e.jsx(ie,{id:"multi-description",value:L.description,onChange:M=>k(L.id,{description:M.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"multi-is-registered",checked:L.isRegistered,onCheckedChange:M=>k(L.id,{isRegistered:M===!0})}),e.jsx(b,{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(hg,{className:"h-12 w-12 mx-auto mb-2 opacity-50"}),e.jsx("p",{children:"点击左侧卡片编辑"})]})})})]}),e.jsx(at,{children:e.jsx(N,{onClick:H,disabled:!Y||w,children:w?"上传中...":`上传全部 (${T})`})})]})};return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Hs,{className:"max-w-3xl max-h-[90vh] overflow-hidden",children:[e.jsxs(qs,{children:[e.jsxs(Gs,{className:"flex items-center gap-2",children:[e.jsx(fr,{className:"h-5 w-5"}),d==="select"&&"上传表情包 - 选择文件",d==="edit-single"&&"上传表情包 - 填写信息",d==="edit-multiple"&&"上传表情包 - 批量编辑"]}),e.jsxs(Is,{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"&&D(),d==="edit-single"&&C(),d==="edit-multiple"&&$()]})]})})}const Gl="/api/webui/expression";async function Xw(){const n=await Te(`${Gl}/chats`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取聊天列表失败")}return n.json()}async function Kw(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.chat_id&&i.append("chat_id",n.chat_id);const c=await Te(`${Gl}/list?${i}`,{});if(!c.ok){const d=await c.json();throw new Error(d.detail||"获取表达方式列表失败")}return c.json()}async function Jw(n){const i=await Te(`${Gl}/${n}`,{});if(!i.ok){const c=await i.json();throw new Error(c.detail||"获取表达方式详情失败")}return i.json()}async function Zw(n){const i=await Te(`${Gl}/`,{method:"POST",body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"创建表达方式失败")}return i.json()}async function Iw(n,i){const c=await Te(`${Gl}/${n}`,{method:"PATCH",body:JSON.stringify(i)});if(!c.ok){const d=await c.json();throw new Error(d.detail||"更新表达方式失败")}return c.json()}async function Pw(n){const i=await Te(`${Gl}/${n}`,{method:"DELETE"});if(!i.ok){const c=await i.json();throw new Error(c.detail||"删除表达方式失败")}return i.json()}async function Ww(n){const i=await Te(`${Gl}/batch/delete`,{method:"POST",body:JSON.stringify({ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除表达方式失败")}return i.json()}async function e1(){const n=await Te(`${Gl}/stats/summary`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取统计数据失败")}return n.json()}function s1(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,f]=u.useState(0),[x,j]=u.useState(1),[p,w]=u.useState(20),[v,y]=u.useState(""),[S,k]=u.useState(null),[O,Y]=u.useState(!1),[L,R]=u.useState(!1),[H,D]=u.useState(!1),[C,$]=u.useState(null),[G,T]=u.useState(new Set),[M,ne]=u.useState(!1),[fe,_e]=u.useState(""),[Se,je]=u.useState({total:0,recent_7days:0,chat_count:0,top_chats:{}}),[ye,be]=u.useState([]),[A,K]=u.useState(new Map),{toast:E}=Vs(),se=async()=>{try{d(!0);const W=await Kw({page:x,page_size:p,search:v||void 0});i(W.data),f(W.total)}catch(W){E({title:"加载失败",description:W instanceof Error?W.message:"无法加载表达方式",variant:"destructive"})}finally{d(!1)}},_=async()=>{try{const W=await e1();W?.data&&je(W.data)}catch(W){console.error("加载统计数据失败:",W)}},me=async()=>{try{const W=await Xw();if(W?.data){be(W.data);const Ce=new Map;W.data.forEach(Me=>{Ce.set(Me.chat_id,Me.chat_name)}),K(Ce)}}catch(W){console.error("加载聊天列表失败:",W)}},re=W=>A.get(W)||W;u.useEffect(()=>{se(),_(),me()},[x,p,v]);const le=async W=>{try{const Ce=await Jw(W.id);k(Ce.data),Y(!0)}catch(Ce){E({title:"加载详情失败",description:Ce instanceof Error?Ce.message:"无法加载表达方式详情",variant:"destructive"})}},pe=W=>{k(W),R(!0)},Ne=async W=>{try{await Pw(W.id),E({title:"删除成功",description:`已删除表达方式: ${W.situation}`}),$(null),se(),_()}catch(Ce){E({title:"删除失败",description:Ce instanceof Error?Ce.message:"无法删除表达方式",variant:"destructive"})}},he=W=>{const Ce=new Set(G);Ce.has(W)?Ce.delete(W):Ce.add(W),T(Ce)},Q=()=>{G.size===n.length&&n.length>0?T(new Set):T(new Set(n.map(W=>W.id)))},P=async()=>{try{await Ww(Array.from(G)),E({title:"批量删除成功",description:`已删除 ${G.size} 个表达方式`}),T(new Set),ne(!1),se(),_()}catch(W){E({title:"批量删除失败",description:W instanceof Error?W.message:"无法批量删除表达方式",variant:"destructive"})}},q=()=>{const W=parseInt(fe),Ce=Math.ceil(h/p);W>=1&&W<=Ce?(j(W),_e("")):E({title:"无效的页码",description:`请输入1-${Ce}之间的页码`,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(un,{className:"h-8 w-8",strokeWidth:2}),"表达方式管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦的表达方式和话术模板"})]}),e.jsxs(N,{onClick:()=>D(!0),className:"gap-2",children:[e.jsx(ot,{className:"h-4 w-4"}),"新增表达方式"]})]})}),e.jsx(ss,{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(b,{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(zt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索情境、风格或上下文...",value:v,onChange:W=>y(W.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:G.size>0&&e.jsxs("span",{children:["已选择 ",G.size," 个表达方式"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Be,{value:p.toString(),onValueChange:W=>{w(parseInt(W)),j(1),T(new Set)},children:[e.jsx(Le,{id:"page-size",className:"w-20",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"10",children:"10"}),e.jsx(te,{value:"20",children:"20"}),e.jsx(te,{value:"50",children:"50"}),e.jsx(te,{value:"100",children:"100"})]})]}),G.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>T(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:()=>ne(!0),children:[e.jsx(ts,{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(hn,{children:[e.jsx(xn,{children:e.jsxs(dt,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:G.size===n.length&&n.length>0,onCheckedChange:Q})}),e.jsx(Ie,{children:"情境"}),e.jsx(Ie,{children:"风格"}),e.jsx(Ie,{children:"聊天"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c?e.jsx(dt,{children:e.jsx(Fe,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(dt,{children:e.jsx(Fe,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(W=>e.jsxs(dt,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:G.has(W.id),onCheckedChange:()=>he(W.id)})}),e.jsx(Fe,{className:"font-medium max-w-xs truncate",children:W.situation}),e.jsx(Fe,{className:"max-w-xs truncate",children:W.style}),e.jsx(Fe,{className:"max-w-[200px] truncate",title:re(W.chat_id),style:{wordBreak:"keep-all"},children:e.jsx("span",{className:"whitespace-nowrap overflow-hidden text-ellipsis block",children:re(W.chat_id)})}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>pe(W),children:[e.jsx(mn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>le(W),title:"查看详情",children:e.jsx(Dt,{className:"h-4 w-4"})}),e.jsxs(N,{size:"sm",onClick:()=>$(W),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ts,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},W.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:c?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(W=>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:G.has(W.id),onCheckedChange:()=>he(W.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:W.situation,children:W.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:W.style,children:W.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:re(W.chat_id),style:{wordBreak:"keep-all"},children:re(W.chat_id)})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>pe(W),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(mn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>le(W),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:e.jsx(Dt,{className:"h-3 w-3"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>$(W),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(ts,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},W.id))}),h>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:["共 ",h," 条记录,第 ",x," / ",Math.ceil(h/p)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:x===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(x-1),disabled:x===1,children:[e.jsx(Hl,{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:W=>_e(W.target.value),onKeyDown:W=>W.key==="Enter"&&q(),placeholder:x.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(h/p)}),e.jsx(N,{variant:"outline",size:"sm",onClick:q,disabled:!fe,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(x+1),disabled:x>=Math.ceil(h/p),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(h/p)),disabled:x>=Math.ceil(h/p),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(t1,{expression:S,open:O,onOpenChange:Y,chatNameMap:A}),e.jsx(a1,{open:H,onOpenChange:D,chatList:ye,onSuccess:()=>{se(),_(),D(!1)}}),e.jsx(l1,{expression:S,open:L,onOpenChange:R,chatList:ye,onSuccess:()=>{se(),_(),R(!1)}}),e.jsx(ps,{open:!!C,onOpenChange:()=>$(null),children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除表达方式 "',C?.situation,'" 吗? 此操作不可撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>C&&Ne(C),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(n1,{open:M,onOpenChange:ne,onConfirm:P,count:G.size})]})}function t1({expression:n,open:i,onOpenChange:c,chatNameMap:d}){if(!n)return null;const h=x=>x?new Date(x*1e3).toLocaleString("zh-CN"):"-",f=x=>d.get(x)||x;return e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"表达方式详情"}),e.jsx(Is,{children:"查看表达方式的完整信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(rr,{label:"情境",value:n.situation}),e.jsx(rr,{label:"风格",value:n.style}),e.jsx(rr,{label:"聊天",value:f(n.chat_id)}),e.jsx(rr,{icon:ri,label:"记录ID",value:n.id.toString(),mono:!0})]}),e.jsx("div",{className:"grid grid-cols-2 gap-4",children:e.jsx(rr,{icon:li,label:"创建时间",value:h(n.create_date)})})]}),e.jsx(at,{children:e.jsx(N,{onClick:()=>c(!1),children:"关闭"})})]})})}function rr({icon:n,label:i,value:c,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(b,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:X("text-sm",d&&"font-mono",!c&&"text-muted-foreground"),children:c||"-"})]})}function a1({open:n,onOpenChange:i,chatList:c,onSuccess:d}){const[h,f]=u.useState({situation:"",style:"",chat_id:""}),[x,j]=u.useState(!1),{toast:p}=Vs(),w=async()=>{if(!h.situation||!h.style||!h.chat_id){p({title:"验证失败",description:"请填写必填字段:情境、风格和聊天",variant:"destructive"});return}try{j(!0),await Zw(h),p({title:"创建成功",description:"表达方式已创建"}),f({situation:"",style:"",chat_id:""}),d()}catch(v){p({title:"创建失败",description:v instanceof Error?v.message:"无法创建表达方式",variant:"destructive"})}finally{j(!1)}};return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"新增表达方式"}),e.jsx(Is,{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(b,{htmlFor:"situation",children:["情境 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"situation",value:h.situation,onChange:v=>f({...h,situation:v.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"style",children:["风格 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"style",value:h.style,onChange:v=>f({...h,style:v.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(Be,{value:h.chat_id,onValueChange:v=>f({...h,chat_id:v}),children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{children:c.map(v=>e.jsx(te,{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(N,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(N,{onClick:w,disabled:x,children:x?"创建中...":"创建"})]})]})})}function l1({expression:n,open:i,onOpenChange:c,chatList:d,onSuccess:h}){const[f,x]=u.useState({}),[j,p]=u.useState(!1),{toast:w}=Vs();u.useEffect(()=>{n&&x({situation:n.situation,style:n.style,chat_id:n.chat_id})},[n]);const v=async()=>{if(n)try{p(!0),await Iw(n.id,f),w({title:"保存成功",description:"表达方式已更新"}),h()}catch(y){w({title:"保存失败",description:y instanceof Error?y.message:"无法更新表达方式",variant:"destructive"})}finally{p(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"编辑表达方式"}),e.jsx(Is,{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(b,{htmlFor:"edit_situation",children:"情境"}),e.jsx(ie,{id:"edit_situation",value:f.situation||"",onChange:y=>x({...f,situation:y.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit_style",children:"风格"}),e.jsx(ie,{id:"edit_style",value:f.style||"",onChange:y=>x({...f,style:y.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(Be,{value:f.chat_id||"",onValueChange:y=>x({...f,chat_id:y}),children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{children:d.map(y=>e.jsx(te,{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(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:v,disabled:j,children:j?"保存中...":"保存"})]})]})}):null}function n1({open:n,onOpenChange:i,onConfirm:c,count:d}){return e.jsx(ps,{open:n,onOpenChange:i,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认批量删除"}),e.jsxs(us,{children:["您即将删除 ",d," 个表达方式,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:c,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})}const ml="/api/webui/jargon";async function i1(){const n=await Te(`${ml}/chats`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取聊天列表失败")}return n.json()}async function r1(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.chat_id&&i.append("chat_id",n.chat_id),n.is_jargon!==void 0&&n.is_jargon!==null&&i.append("is_jargon",n.is_jargon.toString()),n.is_global!==void 0&&i.append("is_global",n.is_global.toString());const c=await Te(`${ml}/list?${i}`,{});if(!c.ok){const d=await c.json();throw new Error(d.detail||"获取黑话列表失败")}return c.json()}async function c1(n){const i=await Te(`${ml}/${n}`,{});if(!i.ok){const c=await i.json();throw new Error(c.detail||"获取黑话详情失败")}return i.json()}async function o1(n){const i=await Te(`${ml}/`,{method:"POST",body:JSON.stringify(n)});if(!i.ok){const c=await i.json();throw new Error(c.detail||"创建黑话失败")}return i.json()}async function d1(n,i){const c=await Te(`${ml}/${n}`,{method:"PATCH",body:JSON.stringify(i)});if(!c.ok){const d=await c.json();throw new Error(d.detail||"更新黑话失败")}return c.json()}async function u1(n){const i=await Te(`${ml}/${n}`,{method:"DELETE"});if(!i.ok){const c=await i.json();throw new Error(c.detail||"删除黑话失败")}return i.json()}async function m1(n){const i=await Te(`${ml}/batch/delete`,{method:"POST",body:JSON.stringify({ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除黑话失败")}return i.json()}async function h1(){const n=await Te(`${ml}/stats/summary`,{});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取黑话统计失败")}return n.json()}async function x1(n,i){const c=new URLSearchParams;n.forEach(h=>c.append("ids",h.toString())),c.append("is_jargon",i.toString());const d=await Te(`${ml}/batch/set-jargon?${c}`,{method:"POST"});if(!d.ok){const h=await d.json();throw new Error(h.detail||"批量设置黑话状态失败")}return d.json()}function f1(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,f]=u.useState(0),[x,j]=u.useState(1),[p,w]=u.useState(20),[v,y]=u.useState(""),[S,k]=u.useState("all"),[O,Y]=u.useState("all"),[L,R]=u.useState(null),[H,D]=u.useState(!1),[C,$]=u.useState(!1),[G,T]=u.useState(!1),[M,ne]=u.useState(null),[fe,_e]=u.useState(new Set),[Se,je]=u.useState(!1),[ye,be]=u.useState(""),[A,K]=u.useState({total:0,confirmed_jargon:0,confirmed_not_jargon:0,pending:0,global_count:0,complete_count:0,chat_count:0,top_chats:{}}),[E,se]=u.useState([]),{toast:_}=Vs(),me=async()=>{try{d(!0);const ce=await r1({page:x,page_size:p,search:v||void 0,chat_id:S==="all"?void 0:S,is_jargon:O==="all"?void 0:O==="true"?!0:O==="false"?!1:void 0});i(ce.data),f(ce.total)}catch(ce){_({title:"加载失败",description:ce instanceof Error?ce.message:"无法加载黑话列表",variant:"destructive"})}finally{d(!1)}},re=async()=>{try{const ce=await h1();ce?.data&&K(ce.data)}catch(ce){console.error("加载统计数据失败:",ce)}},le=async()=>{try{const ce=await i1();ce?.data&&se(ce.data)}catch(ce){console.error("加载聊天列表失败:",ce)}};u.useEffect(()=>{me(),re(),le()},[x,p,v,S,O]);const pe=async ce=>{try{const De=await c1(ce.id);R(De.data),D(!0)}catch(De){_({title:"加载详情失败",description:De instanceof Error?De.message:"无法加载黑话详情",variant:"destructive"})}},Ne=ce=>{R(ce),$(!0)},he=async ce=>{try{await u1(ce.id),_({title:"删除成功",description:`已删除黑话: ${ce.content}`}),ne(null),me(),re()}catch(De){_({title:"删除失败",description:De instanceof Error?De.message:"无法删除黑话",variant:"destructive"})}},Q=ce=>{const De=new Set(fe);De.has(ce)?De.delete(ce):De.add(ce),_e(De)},P=()=>{fe.size===n.length&&n.length>0?_e(new Set):_e(new Set(n.map(ce=>ce.id)))},q=async()=>{try{await m1(Array.from(fe)),_({title:"批量删除成功",description:`已删除 ${fe.size} 个黑话`}),_e(new Set),je(!1),me(),re()}catch(ce){_({title:"批量删除失败",description:ce instanceof Error?ce.message:"无法批量删除黑话",variant:"destructive"})}},W=async ce=>{try{await x1(Array.from(fe),ce),_({title:"操作成功",description:`已将 ${fe.size} 个词条设为${ce?"黑话":"非黑话"}`}),_e(new Set),me(),re()}catch(De){_({title:"操作失败",description:De instanceof Error?De.message:"批量设置失败",variant:"destructive"})}},Ce=()=>{const ce=parseInt(ye),De=Math.ceil(h/p);ce>=1&&ce<=De?(j(ce),be("")):_({title:"无效的页码",description:`请输入1-${De}之间的页码`,variant:"destructive"})},Me=ce=>ce===!0?e.jsxs($e,{variant:"default",className:"bg-green-600 hover:bg-green-700",children:[e.jsx($t,{className:"h-3 w-3 mr-1"}),"是黑话"]}):ce===!1?e.jsxs($e,{variant:"secondary",children:[e.jsx(dl,{className:"h-3 w-3 mr-1"}),"非黑话"]}):e.jsxs($e,{variant:"outline",children:[e.jsx(mg,{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(zb,{className:"h-8 w-8",strokeWidth:2}),"黑话管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦学习到的黑话和俚语"})]}),e.jsxs(N,{onClick:()=>T(!0),className:"gap-2",children:[e.jsx(ot,{className:"h-4 w-4"}),"新增黑话"]})]})}),e.jsx(ss,{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:A.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:A.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:A.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:A.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:A.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:A.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:A.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(b,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索内容、含义...",value:v,onChange:ce=>y(ce.target.value),className:"pl-9"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(b,{children:"聊天筛选"}),e.jsxs(Be,{value:S,onValueChange:k,children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"全部聊天"})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部聊天"}),E.map(ce=>e.jsx(te,{value:ce.chat_id,children:ce.chat_name},ce.chat_id))]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(b,{children:"状态筛选"}),e.jsxs(Be,{value:O,onValueChange:Y,children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"全部状态"})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部状态"}),e.jsx(te,{value:"true",children:"是黑话"}),e.jsx(te,{value:"false",children:"非黑话"}),e.jsx(te,{value:"null",children:"未判定"})]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(b,{htmlFor:"page-size",children:"每页显示"}),e.jsxs(Be,{value:p.toString(),onValueChange:ce=>{w(parseInt(ce)),j(1),_e(new Set)},children:[e.jsx(Le,{id:"page-size",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"10",children:"10"}),e.jsx(te,{value:"20",children:"20"}),e.jsx(te,{value:"50",children:"50"}),e.jsx(te,{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(N,{variant:"outline",size:"sm",onClick:()=>W(!0),children:[e.jsx($t,{className:"h-4 w-4 mr-1"}),"标记为黑话"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>W(!1),children:[e.jsx(dl,{className:"h-4 w-4 mr-1"}),"标记为非黑话"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>_e(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:()=>je(!0),children:[e.jsx(ts,{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(hn,{children:[e.jsx(xn,{children:e.jsxs(dt,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:fe.size===n.length&&n.length>0,onCheckedChange:P})}),e.jsx(Ie,{children:"内容"}),e.jsx(Ie,{children:"含义"}),e.jsx(Ie,{children:"聊天"}),e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{className:"text-center",children:"次数"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c?e.jsx(dt,{children:e.jsx(Fe,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(dt,{children:e.jsx(Fe,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(ce=>e.jsxs(dt,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:fe.has(ce.id),onCheckedChange:()=>Q(ce.id)})}),e.jsx(Fe,{className:"font-medium max-w-[200px]",children:e.jsxs("div",{className:"flex items-center gap-2",children:[ce.is_global&&e.jsx("span",{title:"全局黑话",children:e.jsx(Lu,{className:"h-4 w-4 text-blue-500 flex-shrink-0"})}),e.jsx("span",{className:"truncate",title:ce.content,children:ce.content})]})}),e.jsx(Fe,{className:"max-w-[200px] truncate",title:ce.meaning||"",children:ce.meaning||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Fe,{className:"max-w-[150px] truncate",title:ce.chat_name||ce.chat_id,children:ce.chat_name||ce.chat_id}),e.jsx(Fe,{children:Me(ce.is_jargon)}),e.jsx(Fe,{className:"text-center",children:ce.count}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>Ne(ce),children:[e.jsx(mn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>pe(ce),title:"查看详情",children:e.jsx(Dt,{className:"h-4 w-4"})}),e.jsxs(N,{size:"sm",onClick:()=>ne(ce),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ts,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},ce.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:c?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(ce=>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:fe.has(ce.id),onCheckedChange:()=>Q(ce.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:[ce.is_global&&e.jsx(Lu,{className:"h-4 w-4 text-blue-500 flex-shrink-0"}),e.jsx("h3",{className:"font-semibold text-sm break-all",children:ce.content})]}),ce.meaning&&e.jsx("p",{className:"text-sm text-muted-foreground break-all",children:ce.meaning}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[Me(ce.is_jargon),e.jsxs("span",{className:"text-muted-foreground",children:["次数: ",ce.count]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate",children:["聊天: ",ce.chat_name||ce.chat_id]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>Ne(ce),className:"text-xs px-2 py-1 h-auto",children:[e.jsx(mn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>pe(ce),className:"text-xs px-2 py-1 h-auto",children:e.jsx(Dt,{className:"h-3 w-3"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>ne(ce),className:"text-xs px-2 py-1 h-auto text-destructive hover:text-destructive",children:[e.jsx(ts,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},ce.id))}),h>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:["共 ",h," 条记录,第 ",x," / ",Math.ceil(h/p)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:x===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(x-1),disabled:x===1,children:[e.jsx(Hl,{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:ye,onChange:ce=>be(ce.target.value),onKeyDown:ce=>ce.key==="Enter"&&Ce(),placeholder:x.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(h/p)}),e.jsx(N,{variant:"outline",size:"sm",onClick:Ce,disabled:!ye,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(x+1),disabled:x>=Math.ceil(h/p),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(h/p)),disabled:x>=Math.ceil(h/p),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(p1,{jargon:L,open:H,onOpenChange:D}),e.jsx(g1,{open:G,onOpenChange:T,chatList:E,onSuccess:()=>{me(),re(),T(!1)}}),e.jsx(j1,{jargon:L,open:C,onOpenChange:$,chatList:E,onSuccess:()=>{me(),re(),$(!1)}}),e.jsx(ps,{open:!!M,onOpenChange:()=>ne(null),children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除黑话 "',M?.content,'" 吗?此操作不可撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>M&&he(M),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(ps,{open:Se,onOpenChange:je,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认批量删除"}),e.jsxs(us,{children:["您即将删除 ",fe.size," 个黑话,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:q,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})]})}function p1({jargon:n,open:i,onOpenChange:c}){return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] grid grid-rows-[auto_1fr_auto] overflow-hidden",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"黑话详情"}),e.jsx(Is,{children:"查看黑话的完整信息"})]}),e.jsx(ss,{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(Ou,{icon:ri,label:"记录ID",value:n.id.toString(),mono:!0}),e.jsx(Ou,{label:"使用次数",value:n.count.toString()})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{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(b,{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((h,f)=>e.jsxs("div",{children:[f>0&&e.jsx("hr",{className:"my-3 border-border"}),e.jsx("div",{className:"whitespace-pre-wrap",children:h})]},f)):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(b,{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.meaning||"-"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Ou,{label:"聊天",value:n.chat_name||n.chat_id}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{className:"text-xs text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"flex items-center gap-2",children:[n.is_jargon===!0&&e.jsx($e,{variant:"default",className:"bg-green-600",children:"是黑话"}),n.is_jargon===!1&&e.jsx($e,{variant:"secondary",children:"非黑话"}),n.is_jargon===null&&e.jsx($e,{variant:"outline",children:"未判定"}),n.is_global&&e.jsx($e,{variant:"outline",className:"border-blue-500 text-blue-500",children:"全局"}),n.is_complete&&e.jsx($e,{variant:"outline",className:"border-purple-500 text-purple-500",children:"推断完成"})]})]})]}),n.inference_with_context&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(b,{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(b,{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(at,{className:"flex-shrink-0",children:e.jsx(N,{onClick:()=>c(!1),children:"关闭"})})]})}):null}function Ou({icon:n,label:i,value:c,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(b,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:X("text-sm",d&&"font-mono",!c&&"text-muted-foreground"),children:c||"-"})]})}function g1({open:n,onOpenChange:i,chatList:c,onSuccess:d}){const[h,f]=u.useState({content:"",meaning:"",chat_id:"",is_global:!1}),[x,j]=u.useState(!1),{toast:p}=Vs(),w=async()=>{if(!h.content||!h.chat_id){p({title:"验证失败",description:"请填写必填字段:内容和聊天",variant:"destructive"});return}try{j(!0),await o1(h),p({title:"创建成功",description:"黑话已创建"}),f({content:"",meaning:"",chat_id:"",is_global:!1}),d()}catch(v){p({title:"创建失败",description:v instanceof Error?v.message:"无法创建黑话",variant:"destructive"})}finally{j(!1)}};return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"新增黑话"}),e.jsx(Is,{children:"创建新的黑话记录"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"content",children:["内容 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"content",value:h.content,onChange:v=>f({...h,content:v.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"meaning",children:"含义"}),e.jsx(Bs,{id:"meaning",value:h.meaning||"",onChange:v=>f({...h,meaning:v.target.value}),placeholder:"输入黑话含义(可选)",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(b,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(Be,{value:h.chat_id,onValueChange:v=>f({...h,chat_id:v}),children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{children:c.map(v=>e.jsx(te,{value:v.chat_id,children:v.chat_name},v.chat_id))})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{id:"is_global",checked:h.is_global,onCheckedChange:v=>f({...h,is_global:v})}),e.jsx(b,{htmlFor:"is_global",children:"设为全局黑话"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(N,{onClick:w,disabled:x,children:x?"创建中...":"创建"})]})]})})}function j1({jargon:n,open:i,onOpenChange:c,chatList:d,onSuccess:h}){const[f,x]=u.useState({}),[j,p]=u.useState(!1),{toast:w}=Vs();u.useEffect(()=>{n&&x({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 v=async()=>{if(n)try{p(!0),await d1(n.id,f),w({title:"保存成功",description:"黑话已更新"}),h()}catch(y){w({title:"保存失败",description:y instanceof Error?y.message:"无法更新黑话",variant:"destructive"})}finally{p(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"编辑黑话"}),e.jsx(Is,{children:"修改黑话的信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit_content",children:"内容"}),e.jsx(ie,{id:"edit_content",value:f.content||"",onChange:y=>x({...f,content:y.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit_meaning",children:"含义"}),e.jsx(Bs,{id:"edit_meaning",value:f.meaning||"",onChange:y=>x({...f,meaning:y.target.value}),placeholder:"输入黑话含义",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(Be,{value:f.chat_id||"",onValueChange:y=>x({...f,chat_id:y}),children:[e.jsx(Le,{children:e.jsx(He,{placeholder:"选择关联的聊天"})}),e.jsx(Ue,{children:d.map(y=>e.jsx(te,{value:y.chat_id,children:y.chat_name},y.chat_id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"黑话状态"}),e.jsxs(Be,{value:f.is_jargon===null?"null":f.is_jargon?.toString()||"null",onValueChange:y=>x({...f,is_jargon:y==="null"?null:y==="true"}),children:[e.jsx(Le,{children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"null",children:"未判定"}),e.jsx(te,{value:"true",children:"是黑话"}),e.jsx(te,{value:"false",children:"非黑话"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Qe,{id:"edit_is_global",checked:f.is_global,onCheckedChange:y=>x({...f,is_global:y})}),e.jsx(b,{htmlFor:"edit_is_global",children:"全局黑话"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:v,disabled:j,children:j?"保存中...":"保存"})]})]})}):null}const mi="/api/webui/person";async function v1(n){const i=new URLSearchParams;n.page&&i.append("page",n.page.toString()),n.page_size&&i.append("page_size",n.page_size.toString()),n.search&&i.append("search",n.search),n.is_known!==void 0&&i.append("is_known",n.is_known.toString()),n.platform&&i.append("platform",n.platform);const c=await Te(`${mi}/list?${i}`,{headers:Ls()});if(!c.ok){const d=await c.json();throw new Error(d.detail||"获取人物列表失败")}return c.json()}async function N1(n){const i=await Te(`${mi}/${n}`,{headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"获取人物详情失败")}return i.json()}async function b1(n,i){const c=await Te(`${mi}/${n}`,{method:"PATCH",headers:Ls(),body:JSON.stringify(i)});if(!c.ok){const d=await c.json();throw new Error(d.detail||"更新人物信息失败")}return c.json()}async function y1(n){const i=await Te(`${mi}/${n}`,{method:"DELETE",headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"删除人物信息失败")}return i.json()}async function w1(){const n=await Te(`${mi}/stats/summary`,{headers:Ls()});if(!n.ok){const i=await n.json();throw new Error(i.detail||"获取统计数据失败")}return n.json()}async function _1(n){const i=await Te(`${mi}/batch/delete`,{method:"POST",headers:Ls(),body:JSON.stringify({person_ids:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"批量删除失败")}return i.json()}function S1(){const[n,i]=u.useState([]),[c,d]=u.useState(!0),[h,f]=u.useState(0),[x,j]=u.useState(1),[p,w]=u.useState(20),[v,y]=u.useState(""),[S,k]=u.useState(void 0),[O,Y]=u.useState(void 0),[L,R]=u.useState(null),[H,D]=u.useState(!1),[C,$]=u.useState(!1),[G,T]=u.useState(null),[M,ne]=u.useState({total:0,known:0,unknown:0,platforms:{}}),[fe,_e]=u.useState(new Set),[Se,je]=u.useState(!1),[ye,be]=u.useState(""),{toast:A}=Vs(),K=async()=>{try{d(!0);const q=await v1({page:x,page_size:p,search:v||void 0,is_known:S,platform:O});i(q.data),f(q.total)}catch(q){A({title:"加载失败",description:q instanceof Error?q.message:"无法加载人物信息",variant:"destructive"})}finally{d(!1)}},E=async()=>{try{const q=await w1();q?.data&&ne(q.data)}catch(q){console.error("加载统计数据失败:",q)}};u.useEffect(()=>{K(),E()},[x,p,v,S,O]);const se=async q=>{try{const W=await N1(q.person_id);R(W.data),D(!0)}catch(W){A({title:"加载详情失败",description:W instanceof Error?W.message:"无法加载人物详情",variant:"destructive"})}},_=q=>{R(q),$(!0)},me=async q=>{try{await y1(q.person_id),A({title:"删除成功",description:`已删除人物信息: ${q.person_name||q.nickname||q.user_id}`}),T(null),K(),E()}catch(W){A({title:"删除失败",description:W instanceof Error?W.message:"无法删除人物信息",variant:"destructive"})}},re=u.useMemo(()=>Object.keys(M.platforms),[M.platforms]),le=q=>{const W=new Set(fe);W.has(q)?W.delete(q):W.add(q),_e(W)},pe=()=>{fe.size===n.length&&n.length>0?_e(new Set):_e(new Set(n.map(q=>q.person_id)))},Ne=()=>{if(fe.size===0){A({title:"未选择任何人物",description:"请先选择要删除的人物",variant:"destructive"});return}je(!0)},he=async()=>{try{const q=await _1(Array.from(fe));A({title:"批量删除完成",description:q.message}),_e(new Set),je(!1),K(),E()}catch(q){A({title:"批量删除失败",description:q instanceof Error?q.message:"批量删除失败",variant:"destructive"})}},Q=()=>{const q=parseInt(ye),W=Math.ceil(h/p);q>=1&&q<=W?(j(q),be("")):A({title:"无效的页码",description:`请输入1-${W}之间的页码`,variant:"destructive"})},P=q=>q?new Date(q*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(Uu,{className:"h-8 w-8",strokeWidth:2}),"人物信息管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦认识的所有人物信息"})]})})}),e.jsx(ss,{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:M.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:M.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:M.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(b,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative mt-1.5",children:[e.jsx(zt,{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:q=>y(q.target.value),className:"pl-9"})]})]}),e.jsxs("div",{children:[e.jsx(b,{htmlFor:"filter-known",children:"认识状态"}),e.jsxs(Be,{value:S===void 0?"all":S.toString(),onValueChange:q=>{k(q==="all"?void 0:q==="true"),j(1)},children:[e.jsx(Le,{id:"filter-known",className:"mt-1.5",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部"}),e.jsx(te,{value:"true",children:"已认识"}),e.jsx(te,{value:"false",children:"未认识"})]})]})]}),e.jsxs("div",{children:[e.jsx(b,{htmlFor:"filter-platform",children:"平台"}),e.jsxs(Be,{value:O||"all",onValueChange:q=>{Y(q==="all"?void 0:q),j(1)},children:[e.jsx(Le,{id:"filter-platform",className:"mt-1.5",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部平台"}),re.map(q=>e.jsxs(te,{value:q,children:[q," (",M.platforms[q],")"]},q))]})]})]})]}),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(b,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Be,{value:p.toString(),onValueChange:q=>{w(parseInt(q)),j(1),_e(new Set)},children:[e.jsx(Le,{id:"page-size",className:"w-20",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"10",children:"10"}),e.jsx(te,{value:"20",children:"20"}),e.jsx(te,{value:"50",children:"50"}),e.jsx(te,{value:"100",children:"100"})]})]}),fe.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>_e(new Set),children:"取消选择"}),e.jsxs(N,{variant:"destructive",size:"sm",onClick:Ne,children:[e.jsx(ts,{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(hn,{children:[e.jsx(xn,{children:e.jsxs(dt,{children:[e.jsx(Ie,{className:"w-12",children:e.jsx(jt,{checked:n.length>0&&fe.size===n.length,onCheckedChange:pe,"aria-label":"全选"})}),e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{children:"名称"}),e.jsx(Ie,{children:"昵称"}),e.jsx(Ie,{children:"平台"}),e.jsx(Ie,{children:"用户ID"}),e.jsx(Ie,{children:"最后更新"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c?e.jsx(dt,{children:e.jsx(Fe,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(dt,{children:e.jsx(Fe,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(q=>e.jsxs(dt,{children:[e.jsx(Fe,{children:e.jsx(jt,{checked:fe.has(q.person_id),onCheckedChange:()=>le(q.person_id),"aria-label":`选择 ${q.person_name||q.nickname||q.user_id}`})}),e.jsx(Fe,{children:e.jsx("div",{className:X("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium",q.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:q.is_known?"已认识":"未认识"})}),e.jsx(Fe,{className:"font-medium",children:q.person_name||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Fe,{children:q.nickname||"-"}),e.jsx(Fe,{children:q.platform}),e.jsx(Fe,{className:"font-mono text-sm",children:q.user_id}),e.jsx(Fe,{className:"text-sm text-muted-foreground",children:P(q.last_know)}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(N,{variant:"default",size:"sm",onClick:()=>se(q),children:[e.jsx(Dt,{className:"h-4 w-4 mr-1"}),"详情"]}),e.jsxs(N,{variant:"default",size:"sm",onClick:()=>_(q),children:[e.jsx(mn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsxs(N,{size:"sm",onClick:()=>T(q),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(ts,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},q.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:c?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(q=>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:fe.has(q.person_id),onCheckedChange:()=>le(q.person_id),className:"mt-1"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:X("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium mb-2",q.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:q.is_known?"已认识":"未认识"}),e.jsx("h3",{className:"font-semibold text-sm line-clamp-1 w-full break-all",children:q.person_name||e.jsx("span",{className:"text-muted-foreground",children:"未命名"})}),q.nickname&&e.jsxs("p",{className:"text-xs text-muted-foreground mt-1 line-clamp-1 w-full break-all",children:["昵称: ",q.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:q.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:q.user_id,children:q.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:P(q.last_know)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>se(q),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(Dt,{className:"h-3 w-3 mr-1"}),"查看"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>_(q),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(mn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>T(q),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(ts,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},q.id))}),h>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:["共 ",h," 条记录,第 ",x," / ",Math.ceil(h/p)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(1),disabled:x===1,className:"hidden sm:flex",children:e.jsx(di,{className:"h-4 w-4"})}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(x-1),disabled:x===1,children:[e.jsx(Hl,{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:ye,onChange:q=>be(q.target.value),onKeyDown:q=>q.key==="Enter"&&Q(),placeholder:x.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(h/p)}),e.jsx(N,{variant:"outline",size:"sm",onClick:Q,disabled:!ye,className:"h-8",children:"跳转"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>j(x+1),disabled:x>=Math.ceil(h/p),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(ul,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>j(Math.ceil(h/p)),disabled:x>=Math.ceil(h/p),className:"hidden sm:flex",children:e.jsx(ui,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(C1,{person:L,open:H,onOpenChange:D}),e.jsx(k1,{person:L,open:C,onOpenChange:$,onSuccess:()=>{K(),E(),$(!1)}}),e.jsx(ps,{open:!!G,onOpenChange:()=>T(null),children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认删除"}),e.jsxs(us,{children:['确定要删除人物信息 "',G?.person_name||G?.nickname||G?.user_id,'" 吗? 此操作不可撤销。']})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:()=>G&&me(G),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(ps,{open:Se,onOpenChange:je,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"确认批量删除"}),e.jsxs(us,{children:["确定要删除选中的 ",fe.size," 个人物信息吗? 此操作不可撤销。"]})]}),e.jsxs(os,{children:[e.jsx(hs,{children:"取消"}),e.jsx(ms,{onClick:he,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})})]})}function C1({person:n,open:i,onOpenChange:c}){if(!n)return null;const d=h=>h?new Date(h*1e3).toLocaleString("zh-CN"):"-";return e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"人物详情"}),e.jsxs(Is,{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(nl,{icon:Wc,label:"人物名称",value:n.person_name}),e.jsx(nl,{icon:un,label:"昵称",value:n.nickname}),e.jsx(nl,{icon:ri,label:"用户ID",value:n.user_id,mono:!0}),e.jsx(nl,{icon:ri,label:"人物ID",value:n.person_id,mono:!0}),e.jsx(nl,{label:"平台",value:n.platform}),e.jsx(nl,{label:"状态",value:n.is_known?"已认识":"未认识"})]}),n.name_reason&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(b,{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(b,{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(b,{className:"text-xs text-muted-foreground",children:"群昵称"}),e.jsx("div",{className:"mt-2 space-y-1",children:n.group_nick_name.map((h,f)=>e.jsxs("div",{className:"text-sm flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:h.group_id}),e.jsx("span",{children:"→"}),e.jsx("span",{children:h.group_nick_name})]},f))})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(nl,{icon:li,label:"认识时间",value:d(n.know_times)}),e.jsx(nl,{icon:li,label:"首次记录",value:d(n.know_since)}),e.jsx(nl,{icon:li,label:"最后更新",value:d(n.last_know)})]})]}),e.jsx(at,{children:e.jsx(N,{onClick:()=>c(!1),children:"关闭"})})]})})}function nl({icon:n,label:i,value:c,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(b,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:X("text-sm",d&&"font-mono",!c&&"text-muted-foreground"),children:c||"-"})]})}function k1({person:n,open:i,onOpenChange:c,onSuccess:d}){const[h,f]=u.useState({}),[x,j]=u.useState(!1),{toast:p}=Vs();u.useEffect(()=>{n&&f({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 w=async()=>{if(n)try{j(!0),await b1(n.person_id,h),p({title:"保存成功",description:"人物信息已更新"}),d()}catch(v){p({title:"保存失败",description:v instanceof Error?v.message:"无法更新人物信息",variant:"destructive"})}finally{j(!1)}};return n?e.jsx($s,{open:i,onOpenChange:c,children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"编辑人物信息"}),e.jsxs(Is,{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(b,{htmlFor:"person_name",children:"人物名称"}),e.jsx(ie,{id:"person_name",value:h.person_name||"",onChange:v=>f({...h,person_name:v.target.value}),placeholder:"为这个人设置一个名称"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"nickname",children:"昵称"}),e.jsx(ie,{id:"nickname",value:h.nickname||"",onChange:v=>f({...h,nickname:v.target.value}),placeholder:"昵称"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"name_reason",children:"名称设定原因"}),e.jsx(Bs,{id:"name_reason",value:h.name_reason||"",onChange:v=>f({...h,name_reason:v.target.value}),placeholder:"为什么这样称呼这个人?",rows:2})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"memory_points",children:"个人印象"}),e.jsx(Bs,{id:"memory_points",value:h.memory_points||"",onChange:v=>f({...h,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(b,{htmlFor:"is_known",className:"text-base font-medium",children:"已认识"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"标记是否已经认识这个人"})]}),e.jsx(Qe,{id:"is_known",checked:h.is_known,onCheckedChange:v=>f({...h,is_known:v})})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>c(!1),children:"取消"}),e.jsx(N,{onClick:w,disabled:x,children:x?"保存中...":"保存"})]})]})}):null}var T1=fy();const pp=gN(T1),em="/api/webui";async function E1(n=100,i="all"){const c=`${em}/knowledge/graph?limit=${n}&node_type=${i}`,d=await fetch(c);if(!d.ok)throw new Error(`获取知识图谱失败: ${d.status}`);return d.json()}async function z1(){const n=await fetch(`${em}/knowledge/stats`);if(!n.ok)throw new Error("获取知识图谱统计信息失败");return n.json()}async function A1(n){const i=await fetch(`${em}/knowledge/search?query=${encodeURIComponent(n)}`);if(!i.ok)throw new Error("搜索知识节点失败");return i.json()}const Hg=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(eo,{type:"target",position:so.Top}),e.jsx("div",{className:"font-semibold text-white text-sm truncate max-w-[200px]",title:n.content,children:n.label}),e.jsx(eo,{type:"source",position:so.Bottom})]}));Hg.displayName="EntityNode";const qg=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(eo,{type:"target",position:so.Top}),e.jsx("div",{className:"font-medium text-white text-xs truncate max-w-[150px]",title:n.content,children:n.label}),e.jsx(eo,{type:"source",position:so.Bottom})]}));qg.displayName="ParagraphNode";const M1={entity:Hg,paragraph:qg};function D1(n,i){const c=new pp.graphlib.Graph;c.setDefaultEdgeLabel(()=>({})),c.setGraph({rankdir:"TB",ranksep:100,nodesep:80});const d=[],h=[];return n.forEach(f=>{c.setNode(f.id,{width:150,height:50})}),i.forEach(f=>{c.setEdge(f.source,f.target)}),pp.layout(c),n.forEach(f=>{const x=c.node(f.id);d.push({id:f.id,type:f.type,position:{x:x.x-75,y:x.y-25},data:{label:f.content.slice(0,20)+(f.content.length>20?"...":""),content:f.content}})}),i.forEach((f,x)=>{const j={id:`edge-${x}`,source:f.source,target:f.target,animated:n.length<=200&&f.weight>5,style:{strokeWidth:Math.min(f.weight/2,5),opacity:.6}};f.weight>10&&n.length<100&&(j.label=`${f.weight.toFixed(0)}`),h.push(j)}),{nodes:d,edges:h}}function O1(){const n=ja(),[i,c]=u.useState(!1),[d,h]=u.useState(null),[f,x]=u.useState(""),[j,p]=u.useState("all"),[w,v]=u.useState(50),[y,S]=u.useState("50"),[k,O]=u.useState(!1),[Y,L]=u.useState(!0),[R,H]=u.useState(!1),[D,C]=u.useState(!1),[$,G,T]=py([]),[M,ne,fe]=gy([]),[_e,Se]=u.useState(0),[je,ye]=u.useState(null),[be,A]=u.useState(null),{toast:K}=Vs(),E=u.useCallback(he=>he.type==="entity"?"#6366f1":he.type==="paragraph"?"#10b981":"#6b7280",[]),se=u.useCallback(async(he=!1)=>{try{if(!he&&w>200){C(!0);return}c(!0);const[Q,P]=await Promise.all([E1(w,j),z1()]);if(h(P),Q.nodes.length===0){K({title:"提示",description:"知识库为空,请先导入知识数据"}),G([]),ne([]);return}const{nodes:q,edges:W}=D1(Q.nodes,Q.edges);G(q),ne(W),Se(q.length),P&&P.total_nodes>w&&K({title:"提示",description:`知识图谱包含 ${P.total_nodes} 个节点,当前显示 ${q.length} 个`}),K({title:"加载成功",description:`已加载 ${q.length} 个节点,${W.length} 条边`})}catch(Q){console.error("加载知识图谱失败:",Q),K({title:"加载失败",description:Q instanceof Error?Q.message:"未知错误",variant:"destructive"})}finally{c(!1)}},[w,j,K]),_=u.useCallback(async()=>{if(!f.trim()){K({title:"提示",description:"请输入搜索关键词"});return}try{const he=await A1(f);if(he.length===0){K({title:"未找到",description:"没有找到匹配的节点"});return}const Q=new Set(he.map(P=>P.id));G(P=>P.map(q=>({...q,style:{...q.style,opacity:Q.has(q.id)?1:.3,filter:Q.has(q.id)?"brightness(1.2)":"brightness(0.8)"}}))),K({title:"搜索完成",description:`找到 ${he.length} 个匹配节点`})}catch(he){console.error("搜索失败:",he),K({title:"搜索失败",description:he instanceof Error?he.message:"未知错误",variant:"destructive"})}},[f,K]),me=u.useCallback(()=>{G(he=>he.map(Q=>({...Q,style:{...Q.style,opacity:1,filter:"brightness(1)"}})))},[]),re=u.useCallback(()=>{L(!1),H(!0),se()},[se]),le=u.useCallback(()=>{C(!1),setTimeout(()=>{se(!0)},0)},[se]),pe=u.useCallback((he,Q)=>{$.find(q=>q.id===Q.id)&&ye({id:Q.id,type:Q.type,content:Q.data.content})},[$]);u.useEffect(()=>{Y||R&&se()},[w,j,Y,R]);const Ne=u.useCallback((he,Q)=>{const P=$.find(Ce=>Ce.id===Q.source),q=$.find(Ce=>Ce.id===Q.target),W=M.find(Ce=>Ce.id===Q.id);P&&q&&W&&A({source:{id:P.id,type:P.type,content:P.data.content},target:{id:q.id,type:q.type,content:q.data.content},edge:{source:Q.source,target:Q.target,weight:parseFloat(Q.label||"0")}})},[$,M]);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($e,{variant:"outline",className:"gap-1",children:[e.jsx(Ic,{className:"h-3 w-3"}),"节点: ",d.total_nodes]}),e.jsxs($e,{variant:"outline",className:"gap-1",children:[e.jsx(xg,{className:"h-3 w-3"}),"边: ",d.total_edges]}),e.jsxs($e,{variant:"outline",className:"gap-1",children:[e.jsx(La,{className:"h-3 w-3"}),"实体: ",d.entity_nodes]}),e.jsxs($e,{variant:"outline",className:"gap-1",children:[e.jsx(Ra,{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:f,onChange:he=>x(he.target.value),onKeyDown:he=>he.key==="Enter"&&_(),className:"flex-1"}),e.jsx(N,{onClick:_,size:"sm",children:e.jsx(zt,{className:"h-4 w-4"})}),e.jsx(N,{onClick:me,variant:"outline",size:"sm",children:"重置"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(Be,{value:j,onValueChange:he=>p(he),children:[e.jsx(Le,{className:"w-[120px]",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部节点"}),e.jsx(te,{value:"entity",children:"仅实体"}),e.jsx(te,{value:"paragraph",children:"仅段落"})]})]}),e.jsxs(Be,{value:w===1e4?"all":k?"custom":w.toString(),onValueChange:he=>{he==="custom"?(O(!0),S(w.toString())):he==="all"?(O(!1),v(1e4)):(O(!1),v(Number(he)))},children:[e.jsx(Le,{className:"w-[120px]",children:e.jsx(He,{})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"50",children:"50 节点"}),e.jsx(te,{value:"100",children:"100 节点"}),e.jsx(te,{value:"200",children:"200 节点"}),e.jsx(te,{value:"500",children:"500 节点"}),e.jsx(te,{value:"1000",children:"1000 节点"}),e.jsx(te,{value:"all",children:"全部 (最多10000)"}),e.jsx(te,{value:"custom",children:"自定义..."})]})]}),k&&e.jsx(ie,{type:"number",min:"50",value:y,onChange:he=>S(he.target.value),onBlur:()=>{const he=parseInt(y);!isNaN(he)&&he>=50?v(he):(S("50"),v(50))},onKeyDown:he=>{if(he.key==="Enter"){const Q=parseInt(y);!isNaN(Q)&&Q>=50?v(Q):(S("50"),v(50))}},placeholder:"最少50个",className:"w-[120px]"}),e.jsx(N,{onClick:()=>se(),variant:"outline",size:"sm",disabled:i,children:e.jsx(Ct,{className:X("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(Ct,{className:"h-8 w-8 animate-spin mx-auto mb-2 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"加载知识图谱中..."})]})}):$.length===0?e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(Ic,{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(jy,{nodes:$,edges:M,onNodesChange:T,onEdgesChange:fe,onNodeClick:pe,onEdgeClick:Ne,nodeTypes:M1,fitView:!0,minZoom:.05,maxZoom:1.5,defaultViewport:{x:0,y:0,zoom:.5},elevateNodesOnSelect:_e<=500,nodesDraggable:_e<=1e3,attributionPosition:"bottom-left",children:[e.jsx(vy,{variant:Ny.Dots,gap:12,size:1}),e.jsx(by,{}),_e<=500&&e.jsx(yy,{nodeColor:E,nodeBorderRadius:8,pannable:!0,zoomable:!0}),e.jsxs(wy,{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:"段落节点"})]}),_e>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:"已禁用动画"}),_e>500&&e.jsx("div",{children:"已禁用缩略图"})]})]})]})]})}),e.jsx($s,{open:!!je,onOpenChange:he=>!he&&ye(null),children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsx(qs,{children:e.jsx(Gs,{children:"节点详情"})}),je&&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($e,{variant:je.type==="entity"?"default":"secondary",children:je.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:je.id})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"内容"}),e.jsx(ss,{className:"mt-1 h-40 p-3 bg-muted rounded",children:e.jsx("p",{className:"text-sm whitespace-pre-wrap",children:je.content})})]})]})]})}),e.jsx($s,{open:!!be,onOpenChange:he=>!he&&A(null),children:e.jsxs(Hs,{className:"max-w-2xl max-h-[80vh] overflow-hidden flex flex-col",children:[e.jsx(qs,{children:e.jsx(Gs,{children:"边详情"})}),be&&e.jsx(ss,{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($e,{variant:"outline",className:"text-base font-mono",children:be.edge.weight.toFixed(4)})})]})]})})]})}),e.jsx(ps,{open:Y,onOpenChange:L,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"加载知识图谱"}),e.jsxs(us,{children:["知识图谱的动态展示会消耗较多系统资源。",e.jsx("br",{}),"确定要加载知识图谱吗?"]})]}),e.jsxs(os,{children:[e.jsx(hs,{onClick:()=>n({to:"/"}),children:"取消 (返回首页)"}),e.jsx(ms,{onClick:re,children:"确认加载"})]})]})}),e.jsx(ps,{open:D,onOpenChange:C,children:e.jsxs(rs,{children:[e.jsxs(cs,{children:[e.jsx(ds,{children:"⚠️ 节点数量较多"}),e.jsx(us,{asChild:!0,children:e.jsxs("div",{children:[e.jsxs("p",{children:["您正在尝试加载 ",e.jsx("strong",{className:"text-orange-600",children:w>=1e4?"全部 (最多10000个)":w})," 个节点。"]}),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(os,{children:[e.jsx(hs,{onClick:()=>{C(!1),w>200&&(v(50),O(!1))},children:"取消"}),e.jsx(ms,{onClick:le,className:"bg-orange-600 hover:bg-orange-700",children:"我了解风险,继续加载"})]})]})})]})}function gp({className:n,classNames:i,showOutsideDays:c=!0,captionLayout:d="label",buttonVariant:h="ghost",formatters:f,components:x,...j}){const p=jg();return e.jsx(Ib,{showOutsideDays:c,className:X("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:w=>w.toLocaleString("default",{month:"short"}),...f},classNames:{root:X("w-fit",p.root),months:X("relative flex flex-col gap-4 md:flex-row",p.months),month:X("flex w-full flex-col gap-4",p.month),nav:X("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",p.nav),button_previous:X(gr({variant:h}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",p.button_previous),button_next:X(gr({variant:h}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",p.button_next),month_caption:X("flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]",p.month_caption),dropdowns:X("flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium",p.dropdowns),dropdown_root:X("has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",p.dropdown_root),dropdown:X("bg-popover absolute inset-0 opacity-0",p.dropdown),caption_label:X("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",p.caption_label),table:"w-full border-collapse",weekdays:X("flex",p.weekdays),weekday:X("text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal",p.weekday),week:X("mt-2 flex w-full",p.week),week_number_header:X("w-[--cell-size] select-none",p.week_number_header),week_number:X("text-muted-foreground select-none text-[0.8rem]",p.week_number),day:X("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",p.day),range_start:X("bg-accent rounded-l-md",p.range_start),range_middle:X("rounded-none",p.range_middle),range_end:X("bg-accent rounded-r-md",p.range_end),today:X("bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",p.today),outside:X("text-muted-foreground aria-selected:text-muted-foreground",p.outside),disabled:X("text-muted-foreground opacity-50",p.disabled),hidden:X("invisible",p.hidden),...i},components:{Root:({className:w,rootRef:v,...y})=>e.jsx("div",{"data-slot":"calendar",ref:v,className:X(w),...y}),Chevron:({className:w,orientation:v,...y})=>v==="left"?e.jsx(Hl,{className:X("size-4",w),...y}):v==="right"?e.jsx(ul,{className:X("size-4",w),...y}):e.jsx(Bl,{className:X("size-4",w),...y}),DayButton:R1,WeekNumber:({children:w,...v})=>e.jsx("td",{...v,children:e.jsx("div",{className:"flex size-[--cell-size] items-center justify-center text-center",children:w})}),...x},...j})}function R1({className:n,day:i,modifiers:c,...d}){const h=jg(),f=u.useRef(null);return u.useEffect(()=>{c.focused&&f.current?.focus()},[c.focused]),e.jsx(N,{ref:f,variant:"ghost",size:"icon","data-day":i.date.toLocaleDateString(),"data-selected-single":c.selected&&!c.range_start&&!c.range_end&&!c.range_middle,"data-range-start":c.range_start,"data-range-end":c.range_end,"data-range-middle":c.range_middle,className:X("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",h.day,n),...d})}const L1={lessThanXSeconds:{one:"不到 1 秒",other:"不到 {{count}} 秒"},xSeconds:{one:"1 秒",other:"{{count}} 秒"},halfAMinute:"半分钟",lessThanXMinutes:{one:"不到 1 分钟",other:"不到 {{count}} 分钟"},xMinutes:{one:"1 分钟",other:"{{count}} 分钟"},xHours:{one:"1 小时",other:"{{count}} 小时"},aboutXHours:{one:"大约 1 小时",other:"大约 {{count}} 小时"},xDays:{one:"1 天",other:"{{count}} 天"},aboutXWeeks:{one:"大约 1 个星期",other:"大约 {{count}} 个星期"},xWeeks:{one:"1 个星期",other:"{{count}} 个星期"},aboutXMonths:{one:"大约 1 个月",other:"大约 {{count}} 个月"},xMonths:{one:"1 个月",other:"{{count}} 个月"},aboutXYears:{one:"大约 1 年",other:"大约 {{count}} 年"},xYears:{one:"1 年",other:"{{count}} 年"},overXYears:{one:"超过 1 年",other:"超过 {{count}} 年"},almostXYears:{one:"将近 1 年",other:"将近 {{count}} 年"}},U1=(n,i,c)=>{let d;const h=L1[n];return typeof h=="string"?d=h:i===1?d=h.one:d=h.other.replace("{{count}}",String(i)),c?.addSuffix?c.comparison&&c.comparison>0?d+"内":d+"前":d},B1={full:"y'年'M'月'd'日' EEEE",long:"y'年'M'月'd'日'",medium:"yyyy-MM-dd",short:"yy-MM-dd"},H1={full:"zzzz a h:mm:ss",long:"z a h:mm:ss",medium:"a h:mm:ss",short:"a h:mm"},q1={full:"{{date}} {{time}}",long:"{{date}} {{time}}",medium:"{{date}} {{time}}",short:"{{date}} {{time}}"},G1={date:vu({formats:B1,defaultWidth:"full"}),time:vu({formats:H1,defaultWidth:"full"}),dateTime:vu({formats:q1,defaultWidth:"full"})};function jp(n,i,c){const d="eeee p";return NN(n,i,c)?d:n.getTime()>i.getTime()?"'下个'"+d:"'上个'"+d}const V1={lastWeek:jp,yesterday:"'昨天' p",today:"'今天' p",tomorrow:"'明天' p",nextWeek:jp,other:"PP p"},F1=(n,i,c,d)=>{const h=V1[n];return typeof h=="function"?h(i,c,d):h},$1={narrow:["前","公元"],abbreviated:["前","公元"],wide:["公元前","公元"]},Q1={narrow:["1","2","3","4"],abbreviated:["第一季","第二季","第三季","第四季"],wide:["第一季度","第二季度","第三季度","第四季度"]},Y1={narrow:["一","二","三","四","五","六","七","八","九","十","十一","十二"],abbreviated:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],wide:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"]},X1={narrow:["日","一","二","三","四","五","六"],short:["日","一","二","三","四","五","六"],abbreviated:["周日","周一","周二","周三","周四","周五","周六"],wide:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]},K1={narrow:{am:"上",pm:"下",midnight:"凌晨",noon:"午",morning:"早",afternoon:"下午",evening:"晚",night:"夜"},abbreviated:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"},wide:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"}},J1={narrow:{am:"上",pm:"下",midnight:"凌晨",noon:"午",morning:"早",afternoon:"下午",evening:"晚",night:"夜"},abbreviated:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"},wide:{am:"上午",pm:"下午",midnight:"凌晨",noon:"中午",morning:"早晨",afternoon:"中午",evening:"晚上",night:"夜间"}},Z1=(n,i)=>{const c=Number(n);switch(i?.unit){case"date":return c.toString()+"日";case"hour":return c.toString()+"时";case"minute":return c.toString()+"分";case"second":return c.toString()+"秒";default:return"第 "+c.toString()}},I1={ordinalNumber:Z1,era:tr({values:$1,defaultWidth:"wide"}),quarter:tr({values:Q1,defaultWidth:"wide",argumentCallback:n=>n-1}),month:tr({values:Y1,defaultWidth:"wide"}),day:tr({values:X1,defaultWidth:"wide"}),dayPeriod:tr({values:K1,defaultWidth:"wide",formattingValues:J1,defaultFormattingWidth:"wide"})},P1=/^(第\s*)?\d+(日|时|分|秒)?/i,W1=/\d+/i,e2={narrow:/^(前)/i,abbreviated:/^(前)/i,wide:/^(公元前|公元)/i},s2={any:[/^(前)/i,/^(公元)/i]},t2={narrow:/^[1234]/i,abbreviated:/^第[一二三四]刻/i,wide:/^第[一二三四]刻钟/i},a2={any:[/(1|一)/i,/(2|二)/i,/(3|三)/i,/(4|四)/i]},l2={narrow:/^(一|二|三|四|五|六|七|八|九|十[二一])/i,abbreviated:/^(一|二|三|四|五|六|七|八|九|十[二一]|\d|1[12])月/i,wide:/^(一|二|三|四|五|六|七|八|九|十[二一])月/i},n2={narrow:[/^一/i,/^二/i,/^三/i,/^四/i,/^五/i,/^六/i,/^七/i,/^八/i,/^九/i,/^十(?!(一|二))/i,/^十一/i,/^十二/i],any:[/^一|1/i,/^二|2/i,/^三|3/i,/^四|4/i,/^五|5/i,/^六|6/i,/^七|7/i,/^八|8/i,/^九|9/i,/^十(?!(一|二))|10/i,/^十一|11/i,/^十二|12/i]},i2={narrow:/^[一二三四五六日]/i,short:/^[一二三四五六日]/i,abbreviated:/^周[一二三四五六日]/i,wide:/^星期[一二三四五六日]/i},r2={any:[/日/i,/一/i,/二/i,/三/i,/四/i,/五/i,/六/i]},c2={any:/^(上午?|下午?|午夜|[中正]午|早上?|下午|晚上?|凌晨|)/i},o2={any:{am:/^上午?/i,pm:/^下午?/i,midnight:/^午夜/i,noon:/^[中正]午/i,morning:/^早上/i,afternoon:/^下午/i,evening:/^晚上?/i,night:/^凌晨/i}},d2={ordinalNumber:bN({matchPattern:P1,parsePattern:W1,valueCallback:n=>parseInt(n,10)}),era:ar({matchPatterns:e2,defaultMatchWidth:"wide",parsePatterns:s2,defaultParseWidth:"any"}),quarter:ar({matchPatterns:t2,defaultMatchWidth:"wide",parsePatterns:a2,defaultParseWidth:"any",valueCallback:n=>n+1}),month:ar({matchPatterns:l2,defaultMatchWidth:"wide",parsePatterns:n2,defaultParseWidth:"any"}),day:ar({matchPatterns:i2,defaultMatchWidth:"wide",parsePatterns:r2,defaultParseWidth:"any"}),dayPeriod:ar({matchPatterns:c2,defaultMatchWidth:"any",parsePatterns:o2,defaultParseWidth:"any"})},Vc={code:"zh-CN",formatDistance:U1,formatLong:G1,formatRelative:F1,localize:I1,match:d2,options:{weekStartsOn:1,firstWeekContainsDate:4}},Fc={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 u2(){const[n,i]=u.useState([]),[c,d]=u.useState(""),[h,f]=u.useState("all"),[x,j]=u.useState("all"),[p,w]=u.useState(void 0),[v,y]=u.useState(void 0),[S,k]=u.useState(!0),[O,Y]=u.useState(!1),[L,R]=u.useState("xs"),[H,D]=u.useState(4),C=u.useRef(null);u.useEffect(()=>{const E=rn.getAllLogs();i(E);const se=rn.onLog(()=>{i(rn.getAllLogs())}),_=rn.onConnectionChange(me=>{Y(me)});return()=>{se(),_()}},[]);const $=u.useMemo(()=>{const E=new Set(n.map(se=>se.module).filter(se=>se&&se.trim()!==""));return Array.from(E).sort()},[n]),G=E=>{switch(E){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=E=>{switch(E){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"}},M=()=>{window.location.reload()},ne=()=>{rn.clearLogs(),i([])},fe=()=>{const E=je.map(re=>`${re.timestamp} [${re.level.padEnd(8)}] [${re.module}] ${re.message}`).join(` +`),se=new Blob([E],{type:"text/plain;charset=utf-8"}),_=URL.createObjectURL(se),me=document.createElement("a");me.href=_,me.download=`logs-${Nu(new Date,"yyyy-MM-dd-HHmmss")}.txt`,me.click(),URL.revokeObjectURL(_)},_e=()=>{k(!S)},Se=()=>{w(void 0),y(void 0)},je=u.useMemo(()=>n.filter(E=>{const se=c===""||E.message.toLowerCase().includes(c.toLowerCase())||E.module.toLowerCase().includes(c.toLowerCase()),_=h==="all"||E.level===h,me=x==="all"||E.module===x;let re=!0;if(p||v){const le=new Date(E.timestamp);if(p){const pe=new Date(p);pe.setHours(0,0,0,0),re=re&&le>=pe}if(v){const pe=new Date(v);pe.setHours(23,59,59,999),re=re&&le<=pe}}return se&&_&&me&&re}),[n,c,h,x,p,v]),ye=Fc[L].rowHeight+H,be=oN({count:je.length,getScrollElement:()=>C.current,estimateSize:()=>ye,overscan:15}),A=u.useRef(!1),K=u.useRef(je.length);return u.useEffect(()=>{const E=C.current;if(!E)return;const se=()=>{if(A.current)return;const{scrollTop:_,scrollHeight:me,clientHeight:re}=E,le=me-_-re;le>100&&S?k(!1):le<50&&!S&&k(!0)};return E.addEventListener("scroll",se,{passive:!0}),()=>E.removeEventListener("scroll",se)},[S]),u.useEffect(()=>{const E=je.length>K.current;K.current=je.length,S&&je.length>0&&E&&(A.current=!0,be.scrollToIndex(je.length-1,{align:"end",behavior:"auto"}),requestAnimationFrame(()=>{requestAnimationFrame(()=>{A.current=!1})}))},[je.length,S,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:X("h-2.5 w-2.5 sm:h-3 sm:w-3 rounded-full",O?"bg-green-500 animate-pulse":"bg-red-500")}),e.jsx("span",{className:"text-xs sm:text-sm text-muted-foreground",children:O?"已连接":"未连接"})]})]}),e.jsx(Ze,{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(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索日志...",value:c,onChange:E=>d(E.target.value),className:"pl-9 h-9 text-sm"})]}),e.jsxs(Be,{value:h,onValueChange:f,children:[e.jsxs(Le,{className:"w-full sm:w-[140px] lg:w-[180px] h-9 text-sm",children:[e.jsx(Ru,{className:"h-4 w-4 mr-2"}),e.jsx(He,{placeholder:"级别"})]}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部级别"}),e.jsx(te,{value:"DEBUG",children:"DEBUG"}),e.jsx(te,{value:"INFO",children:"INFO"}),e.jsx(te,{value:"WARNING",children:"WARNING"}),e.jsx(te,{value:"ERROR",children:"ERROR"}),e.jsx(te,{value:"CRITICAL",children:"CRITICAL"})]})]}),e.jsxs(Be,{value:x,onValueChange:j,children:[e.jsxs(Le,{className:"w-full sm:w-[160px] lg:w-[200px] h-9 text-sm",children:[e.jsx(Ru,{className:"h-4 w-4 mr-2"}),e.jsx(He,{placeholder:"模块"})]}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部模块"}),$.map(E=>e.jsx(te,{value:E,children:E},E))]})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:gap-4",children:[e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:X("w-full sm:w-[200px] lg:w-[240px] justify-start text-left font-normal h-9",!p&&"text-muted-foreground"),children:[e.jsx(Kf,{className:"mr-2 h-4 w-4"}),e.jsx("span",{className:"text-xs sm:text-sm",children:p?Nu(p,"PPP",{locale:Vc}):"开始日期"})]})}),e.jsx(ka,{className:"w-auto p-0",align:"start",children:e.jsx(gp,{mode:"single",selected:p,onSelect:w,initialFocus:!0,locale:Vc})})]}),e.jsxs(Ua,{children:[e.jsx(Ba,{asChild:!0,children:e.jsxs(N,{variant:"outline",size:"sm",className:X("w-full sm:w-[200px] lg:w-[240px] justify-start text-left font-normal h-9",!v&&"text-muted-foreground"),children:[e.jsx(Kf,{className:"mr-2 h-4 w-4"}),e.jsx("span",{className:"text-xs sm:text-sm",children:v?Nu(v,"PPP",{locale:Vc}):"结束日期"})]})}),e.jsx(ka,{className:"w-auto p-0",align:"start",children:e.jsx(gp,{mode:"single",selected:v,onSelect:y,initialFocus:!0,locale:Vc})})]}),(p||v)&&e.jsxs(N,{variant:"outline",size:"sm",onClick:Se,className:"w-full sm:w-auto h-9",children:[e.jsx(dl,{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(N,{variant:S?"default":"outline",size:"sm",onClick:_e,className:"flex-1 sm:flex-none h-9",children:[S?e.jsx(Ab,{className:"h-4 w-4"}):e.jsx(Mb,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:S?"自动滚动":"已暂停"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:M,className:"flex-1 sm:flex-none h-9",children:[e.jsx(Ct,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"刷新"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:ne,className:"flex-1 sm:flex-none h-9",children:[e.jsx(ts,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"清空"})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:fe,className:"flex-1 sm:flex-none h-9",children:[e.jsx(rl,{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:[je.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(Db,{className:"h-4 w-4"}),e.jsx("span",{children:"字号"})]}),e.jsx("div",{className:"flex gap-1",children:Object.keys(Fc).map(E=>e.jsx(N,{variant:L===E?"default":"outline",size:"sm",onClick:()=>R(E),className:"h-7 px-3 text-xs",children:Fc[E].label},E))})]}),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(wa,{value:[H],onValueChange:([E])=>D(E),min:0,max:12,step:2,className:"flex-1"}),e.jsxs("span",{className:"text-xs text-muted-foreground w-8",children:[H,"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(Ze,{className:"bg-black dark:bg-gray-950 border-gray-800 dark:border-gray-900 h-full",children:e.jsx(ss,{viewportRef:C,className:"h-full",children:e.jsx("div",{className:X("p-2 sm:p-3 font-mono relative",Fc[L].class),style:{height:`${be.getTotalSize()}px`},children:je.length===0?e.jsx("div",{className:"text-gray-500 dark:text-gray-600 text-center py-8 text-sm",children:"暂无日志数据"}):be.getVirtualItems().map(E=>{const se=je[E.index];return e.jsxs("div",{"data-index":E.index,ref:be.measureElement,className:X("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(${E.start}px)`,paddingTop:`${H/2}px`,paddingBottom:`${H/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:X("font-semibold",G(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:X("flex-shrink-0 w-[65px] lg:w-[75px] font-semibold",G(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})]})]},E.key)})})})})})]})}const m2="Mai-with-u",h2="plugin-repo",x2="main",f2="plugin_details.json";async function p2(){try{const n=await Te("/api/webui/plugins/fetch-raw",{method:"POST",body:JSON.stringify({owner:m2,repo:h2,branch:x2,file_path:f2})});if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const i=await n.json();if(!i.success||!i.data)throw new Error(i.error||"获取插件列表失败");return JSON.parse(i.data).filter(h=>!h?.id||!h?.manifest?(console.warn("跳过无效插件数据:",h),!1):!h.manifest.name||!h.manifest.version?(console.warn("跳过缺少必需字段的插件:",h.id),!1):!0).map(h=>({id:h.id,manifest:{manifest_version:h.manifest.manifest_version||1,name:h.manifest.name,version:h.manifest.version,description:h.manifest.description||"",author:h.manifest.author||{name:"Unknown"},license:h.manifest.license||"Unknown",host_application:h.manifest.host_application||{min_version:"0.0.0"},homepage_url:h.manifest.homepage_url,repository_url:h.manifest.repository_url,keywords:h.manifest.keywords||[],categories:h.manifest.categories||[],default_locale:h.manifest.default_locale||"zh-CN",locales_path:h.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 g2(){try{const n=await Te("/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 j2(){try{const n=await Te("/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 v2(n,i,c){const d=n.split(".").map(j=>parseInt(j)||0),h=d[0]||0,f=d[1]||0,x=d[2]||0;if(c.version_majorparseInt(y)||0),p=j[0]||0,w=j[1]||0,v=j[2]||0;if(c.version_major>p||c.version_major===p&&c.version_minor>w||c.version_major===p&&c.version_minor===w&&c.version_patch>v)return!1}return!0}function N2(n,i){const c=window.location.protocol==="https:"?"wss:":"ws:",d=window.location.host,h=new WebSocket(`${c}//${d}/api/webui/ws/plugin-progress`);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 x=JSON.parse(f.data);n(x)}catch(x){console.error("Failed to parse progress data:",x)}},h.onerror=f=>{console.error("Plugin progress WebSocket error:",f),i?.(f)},h.onclose=()=>{console.log("Plugin progress WebSocket disconnected")},h}async function dr(){try{const n=await Te("/api/webui/plugins/installed",{headers:Ls()});if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const i=await n.json();if(!i.success)throw new Error(i.message||"获取已安装插件列表失败");return i.plugins||[]}catch(n){return console.error("Failed to get installed plugins:",n),[]}}function $c(n,i){return i.some(c=>c.id===n)}function Qc(n,i){const c=i.find(d=>d.id===n);if(c)return c.manifest?.version||c.version}async function b2(n,i,c="main"){const d=await Te("/api/webui/plugins/install",{method:"POST",body:JSON.stringify({plugin_id:n,repository_url:i,branch:c})});if(!d.ok){const h=await d.json();throw new Error(h.detail||"安装失败")}return await d.json()}async function y2(n){const i=await Te("/api/webui/plugins/uninstall",{method:"POST",body:JSON.stringify({plugin_id:n})});if(!i.ok){const c=await i.json();throw new Error(c.detail||"卸载失败")}return await i.json()}async function w2(n,i,c="main"){const d=await Te("/api/webui/plugins/update",{method:"POST",body:JSON.stringify({plugin_id:n,repository_url:i,branch:c})});if(!d.ok){const h=await d.json();throw new Error(h.detail||"更新失败")}return await d.json()}async function _2(n){const i=await Te(`/api/webui/plugins/config/${n}/schema`,{headers:Ls()});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取配置 Schema 失败")}const c=await i.json();if(!c.success)throw new Error(c.message||"获取配置 Schema 失败");return c.schema}async function S2(n){const i=await Te(`/api/webui/plugins/config/${n}`,{headers:Ls()});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取配置失败")}const c=await i.json();if(!c.success)throw new Error(c.message||"获取配置失败");return c.config}async function C2(n,i){const c=await Te(`/api/webui/plugins/config/${n}`,{method:"PUT",body:JSON.stringify({config:i})});if(!c.ok){const d=await c.json();throw new Error(d.detail||"保存配置失败")}return await c.json()}async function k2(n){const i=await Te(`/api/webui/plugins/config/${n}/reset`,{method:"POST",headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"重置配置失败")}return await i.json()}async function T2(n){const i=await Te(`/api/webui/plugins/config/${n}/toggle`,{method:"POST",headers:Ls()});if(!i.ok){const c=await i.json();throw new Error(c.detail||"切换状态失败")}return await i.json()}const _r="https://maibot-plugin-stats.maibot-webui.workers.dev";async function Gg(n){try{const i=await fetch(`${_r}/stats/${n}`);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 E2(n,i){try{const c=i||sm(),d=await fetch(`${_r}/stats/like`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,user_id:c})}),h=await d.json();return d.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:d.ok?{success:!0,...h}:{success:!1,error:h.error||"点赞失败"}}catch(c){return console.error("Error liking plugin:",c),{success:!1,error:"网络错误"}}}async function z2(n,i){try{const c=i||sm(),d=await fetch(`${_r}/stats/dislike`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,user_id:c})}),h=await d.json();return d.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:d.ok?{success:!0,...h}:{success:!1,error:h.error||"点踩失败"}}catch(c){return console.error("Error disliking plugin:",c),{success:!1,error:"网络错误"}}}async function A2(n,i,c,d){if(i<1||i>5)return{success:!1,error:"评分必须在 1-5 之间"};try{const h=d||sm(),f=await fetch(`${_r}/stats/rate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,rating:i,comment:c,user_id:h})}),x=await f.json();return f.status===429?{success:!1,error:"每天最多评分 3 次"}:f.ok?{success:!0,...x}:{success:!1,error:x.error||"评分失败"}}catch(h){return console.error("Error rating plugin:",h),{success:!1,error:"网络错误"}}}async function M2(n){try{const i=await fetch(`${_r}/stats/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n})}),c=await i.json();return i.status===429?(console.warn("Download recording rate limited"),{success:!0}):i.ok?{success:!0,...c}:(console.error("Failed to record download:",c.error),{success:!1,error:c.error})}catch(i){return console.error("Error recording download:",i),{success:!1,error:"网络错误"}}}function D2(){const n=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,n.deviceMemory||0].join("|");let c=0;for(let d=0;d{f(!0);const R=await Gg(n);R&&d(R),f(!1)};u.useEffect(()=>{k()},[n]);const O=async()=>{const R=await E2(n);R.success?(S({title:"已点赞",description:"感谢你的支持!"}),k()):S({title:"点赞失败",description:R.error||"未知错误",variant:"destructive"})},Y=async()=>{const R=await z2(n);R.success?(S({title:"已反馈",description:"感谢你的反馈!"}),k()):S({title:"操作失败",description:R.error||"未知错误",variant:"destructive"})},L=async()=>{if(x===0){S({title:"请选择评分",description:"至少选择 1 颗星",variant:"destructive"});return}const R=await A2(n,x,p||void 0);R.success?(S({title:"评分成功",description:"感谢你的评价!"}),y(!1),j(0),w(""),k()):S({title:"评分失败",description:R.error||"未知错误",variant:"destructive"})};return h?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(rl,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ul,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]})]}):c?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:`下载量: ${c.downloads.toLocaleString()}`,children:[e.jsx(rl,{className:"h-4 w-4"}),e.jsx("span",{children:c.downloads.toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`评分: ${c.rating.toFixed(1)} (${c.rating_count} 条评价)`,children:[e.jsx(Ul,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:c.rating.toFixed(1)})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`点赞数: ${c.likes}`,children:[e.jsx(yu,{className:"h-4 w-4"}),e.jsx("span",{children:c.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(rl,{className:"h-5 w-5 text-muted-foreground mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:c.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(Ul,{className:"h-5 w-5 text-yellow-400 mb-1 fill-yellow-400"}),e.jsx("span",{className:"text-2xl font-bold",children:c.rating.toFixed(1)}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[c.rating_count," 条评价"]})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(yu,{className:"h-5 w-5 text-green-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:c.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(Jf,{className:"h-5 w-5 text-red-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:c.dislikes}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"点踩"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(N,{variant:"outline",size:"sm",onClick:O,children:[e.jsx(yu,{className:"h-4 w-4 mr-1"}),"点赞"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:Y,children:[e.jsx(Jf,{className:"h-4 w-4 mr-1"}),"点踩"]}),e.jsxs($s,{open:v,onOpenChange:y,children:[e.jsx(Zu,{asChild:!0,children:e.jsxs(N,{variant:"default",size:"sm",children:[e.jsx(Ul,{className:"h-4 w-4 mr-1"}),"评分"]})}),e.jsxs(Hs,{children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"为插件评分"}),e.jsx(Is,{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(R=>e.jsx("button",{onClick:()=>j(R),className:"focus:outline-none",children:e.jsx(Ul,{className:`h-8 w-8 transition-colors ${R<=x?"fill-yellow-400 text-yellow-400":"text-muted-foreground hover:text-yellow-300"}`})},R))}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[x===0&&"点击星星进行评分",x===1&&"很差",x===2&&"一般",x===3&&"还行",x===4&&"不错",x===5&&"非常好"]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium mb-2 block",children:"评论(可选)"}),e.jsx(Bs,{value:p,onChange:R=>w(R.target.value),placeholder:"分享你的使用体验...",rows:4,maxLength:500}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1 text-right",children:[p.length," / 500"]})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(N,{onClick:L,disabled:x===0,children:"提交评分"})]})]})]})]}),c.recent_ratings&&c.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:c.recent_ratings.map((R,H)=>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(D=>e.jsx(Ul,{className:`h-3 w-3 ${D<=R.rating?"fill-yellow-400 text-yellow-400":"text-muted-foreground"}`},D))}),e.jsx("span",{className:"text-xs text-muted-foreground",children:new Date(R.created_at).toLocaleDateString()})]}),R.comment&&e.jsx("p",{className:"text-sm text-muted-foreground",children:R.comment})]},H))})]})]}):null}const vp={"Group Management":"群组管理","Entertainment & Interaction":"娱乐互动","Utility Tools":"实用工具","Content Generation":"内容生成",Multimedia:"多媒体","External Integration":"外部集成","Data Analysis & Insights":"数据分析与洞察",Other:"其他"};function R2(){const n=ja(),[i,c]=u.useState(null),[d,h]=u.useState(""),[f,x]=u.useState("all"),[j,p]=u.useState("all"),[w,v]=u.useState(!0),[y,S]=u.useState([]),[k,O]=u.useState(!0),[Y,L]=u.useState(null),[R,H]=u.useState(null),[D,C]=u.useState(null),[$,G]=u.useState(null),[,T]=u.useState([]),[M,ne]=u.useState({}),{toast:fe}=Vs(),_e=async _=>{const me=_.map(async pe=>{try{const Ne=await Gg(pe.id);return{id:pe.id,stats:Ne}}catch(Ne){return console.warn(`Failed to load stats for ${pe.id}:`,Ne),{id:pe.id,stats:null}}}),re=await Promise.all(me),le={};re.forEach(({id:pe,stats:Ne})=>{Ne&&(le[pe]=Ne)}),ne(le)};u.useEffect(()=>{let _=null,me=!1;return(async()=>{if(_=N2(le=>{me||(C(le),le.stage==="success"?setTimeout(()=>{me||C(null)},2e3):le.stage==="error"&&(O(!1),L(le.error||"加载失败")))},le=>{console.error("WebSocket error:",le),me||fe({title:"WebSocket 连接失败",description:"无法实时显示加载进度",variant:"destructive"})}),await new Promise(le=>{if(!_){le();return}const pe=()=>{_&&_.readyState===WebSocket.OPEN?(console.log("WebSocket connected, starting to load plugins"),le()):_&&_.readyState===WebSocket.CLOSED?(console.warn("WebSocket closed before loading plugins"),le()):setTimeout(pe,100)};pe()}),!me){const le=await g2();H(le),le.installed||fe({title:"Git 未安装",description:le.error||"请先安装 Git 才能使用插件安装功能",variant:"destructive"})}if(!me){const le=await j2();G(le)}if(!me)try{O(!0),L(null);const le=await p2();if(!me){const pe=await dr();T(pe);const Ne=le.map(he=>{const Q=$c(he.id,pe),P=Qc(he.id,pe);return{...he,installed:Q,installed_version:P}});for(const he of pe)!Ne.some(P=>P.id===he.id)&&he.manifest&&Ne.push({id:he.id,manifest:{manifest_version:he.manifest.manifest_version||1,name:he.manifest.name,version:he.manifest.version,description:he.manifest.description||"",author:he.manifest.author,license:he.manifest.license||"Unknown",host_application:he.manifest.host_application,homepage_url:he.manifest.homepage_url,repository_url:he.manifest.repository_url,keywords:he.manifest.keywords||[],categories:he.manifest.categories||[],default_locale:he.manifest.default_locale||"zh-CN",locales_path:he.manifest.locales_path},downloads:0,rating:0,review_count:0,installed:!0,installed_version:he.manifest.version,published_at:new Date().toISOString(),updated_at:new Date().toISOString()});S(Ne),_e(Ne)}}catch(le){if(!me){const pe=le instanceof Error?le.message:"加载插件列表失败";L(pe),fe({title:"加载失败",description:pe,variant:"destructive"})}}finally{me||O(!1)}})(),()=>{me=!0,_&&_.close()}},[fe]);const Se=_=>{if(!_.installed&&$&&!je(_))return e.jsxs($e,{variant:"destructive",className:"gap-1",children:[e.jsx(Sa,{className:"h-3 w-3"}),"不兼容"]});if(_.installed){const me=_.installed_version?.trim(),re=_.manifest.version?.trim();if(me!==re){const le=me?.split(".").map(Number)||[0,0,0],pe=re?.split(".").map(Number)||[0,0,0];for(let Ne=0;Ne<3;Ne++){if((pe[Ne]||0)>(le[Ne]||0))return e.jsxs($e,{variant:"outline",className:"gap-1 text-orange-600 border-orange-600",children:[e.jsx(Sa,{className:"h-3 w-3"}),"可更新"]});if((pe[Ne]||0)<(le[Ne]||0))break}}return e.jsxs($e,{variant:"default",className:"gap-1",children:[e.jsx(fa,{className:"h-3 w-3"}),"已安装"]})}return null},je=_=>!$||!_.manifest?.host_application?!0:v2(_.manifest.host_application.min_version,_.manifest.host_application.max_version,$),ye=_=>{if(!_.installed||!_.installed_version||!_.manifest?.version)return!1;const me=_.installed_version.trim(),re=_.manifest.version.trim();if(me===re)return!1;const le=me.split(".").map(Number),pe=re.split(".").map(Number);for(let Ne=0;Ne<3;Ne++){if((pe[Ne]||0)>(le[Ne]||0))return!0;if((pe[Ne]||0)<(le[Ne]||0))return!1}return!1},be=y.filter(_=>{if(!_.manifest)return console.warn("[过滤] 跳过无 manifest 的插件:",_.id),!1;const me=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(Ne=>Ne.toLowerCase().includes(d.toLowerCase())),re=f==="all"||_.manifest.categories&&_.manifest.categories.includes(f);let le=!0;j==="installed"?le=_.installed===!0:j==="updates"&&(le=_.installed===!0&&ye(_));const pe=!w||!$||je(_);return me&&re&&le&&pe}),A=()=>{c(null)},K=async _=>{if(!R?.installed){fe({title:"无法安装",description:"Git 未安装",variant:"destructive"});return}if($&&!je(_)){fe({title:"无法安装",description:"插件与当前麦麦版本不兼容",variant:"destructive"});return}try{await b2(_.id,_.manifest.repository_url||"","main"),M2(_.id).catch(re=>{console.warn("Failed to record download:",re)}),fe({title:"安装成功",description:`${_.manifest.name} 已成功安装`});const me=await dr();T(me),S(re=>re.map(le=>{if(le.id===_.id){const pe=$c(le.id,me),Ne=Qc(le.id,me);return{...le,installed:pe,installed_version:Ne}}return le}))}catch(me){fe({title:"安装失败",description:me instanceof Error?me.message:"未知错误",variant:"destructive"})}},E=async _=>{try{await y2(_.id),fe({title:"卸载成功",description:`${_.manifest.name} 已成功卸载`});const me=await dr();T(me),S(re=>re.map(le=>{if(le.id===_.id){const pe=$c(le.id,me),Ne=Qc(le.id,me);return{...le,installed:pe,installed_version:Ne}}return le}))}catch(me){fe({title:"卸载失败",description:me instanceof Error?me.message:"未知错误",variant:"destructive"})}},se=async _=>{if(!R?.installed){fe({title:"无法更新",description:"Git 未安装",variant:"destructive"});return}try{const me=await w2(_.id,_.manifest.repository_url||"","main");fe({title:"更新成功",description:`${_.manifest.name} 已从 ${me.old_version} 更新到 ${me.new_version}`});const re=await dr();T(re),S(le=>le.map(pe=>{if(pe.id===_.id){const Ne=$c(pe.id,re),he=Qc(pe.id,re);return{...pe,installed:Ne,installed_version:he}}return pe}))}catch(me){fe({title:"更新失败",description:me instanceof Error?me.message:"未知错误",variant:"destructive"})}};return e.jsx(ss,{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(N,{onClick:()=>n({to:"/plugin-mirrors"}),children:[e.jsx(Ob,{className:"h-4 w-4 mr-2"}),"配置镜像源"]})]}),R&&!R.installed&&e.jsxs(Ze,{className:"border-orange-600 bg-orange-50 dark:bg-orange-950/20",children:[e.jsx(ys,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(_a,{className:"h-5 w-5 text-orange-600"}),e.jsxs("div",{children:[e.jsx(ws,{className:"text-lg text-orange-900 dark:text-orange-100",children:"Git 未安装"}),e.jsx(ct,{className:"text-orange-800 dark:text-orange-200",children:R.error||"请先安装 Git 才能使用插件安装功能"})]})]})}),e.jsx(Ts,{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(Ze,{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(zt,{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:_=>h(_.target.value),className:"pl-9"})]}),e.jsxs(Be,{value:f,onValueChange:x,children:[e.jsx(Le,{className:"w-full sm:w-[200px]",children:e.jsx(He,{placeholder:"选择分类"})}),e.jsxs(Ue,{children:[e.jsx(te,{value:"all",children:"全部分类"}),e.jsx(te,{value:"Group Management",children:"群组管理"}),e.jsx(te,{value:"Entertainment & Interaction",children:"娱乐互动"}),e.jsx(te,{value:"Utility Tools",children:"实用工具"}),e.jsx(te,{value:"Content Generation",children:"内容生成"}),e.jsx(te,{value:"Multimedia",children:"多媒体"}),e.jsx(te,{value:"External Integration",children:"外部集成"}),e.jsx(te,{value:"Data Analysis & Insights",children:"数据分析与洞察"}),e.jsx(te,{value:"Other",children:"其他"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"compatible-only",checked:w,onCheckedChange:_=>v(_===!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(Ca,{value:j,onValueChange:p,className:"w-full",children:e.jsxs(pa,{className:"grid w-full grid-cols-3",children:[e.jsxs(ns,{value:"all",children:["全部插件 (",y.filter(_=>{if(!_.manifest)return!1;const me=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(pe=>pe.toLowerCase().includes(d.toLowerCase())),re=f==="all"||_.manifest.categories&&_.manifest.categories.includes(f),le=!w||!$||je(_);return me&&re&&le}).length,")"]}),e.jsxs(ns,{value:"installed",children:["已安装 (",y.filter(_=>{if(!_.manifest)return!1;const me=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(pe=>pe.toLowerCase().includes(d.toLowerCase())),re=f==="all"||_.manifest.categories&&_.manifest.categories.includes(f),le=!w||!$||je(_);return _.installed&&me&&re&&le}).length,")"]}),e.jsxs(ns,{value:"updates",children:["可更新 (",y.filter(_=>{if(!_.manifest)return!1;const me=d===""||_.manifest.name?.toLowerCase().includes(d.toLowerCase())||_.manifest.description?.toLowerCase().includes(d.toLowerCase())||_.manifest.keywords&&_.manifest.keywords.some(pe=>pe.toLowerCase().includes(d.toLowerCase())),re=f==="all"||_.manifest.categories&&_.manifest.categories.includes(f),le=!w||!$||je(_);return _.installed&&ye(_)&&me&&re&&le}).length,")"]})]})}),D&&D.stage==="loading"&&e.jsx(Ze,{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(kt,{className:"h-4 w-4 animate-spin"}),e.jsxs("span",{className:"text-sm font-medium",children:[D.operation==="fetch"&&"加载插件列表",D.operation==="install"&&`安装插件${D.plugin_id?`: ${D.plugin_id}`:""}`,D.operation==="uninstall"&&`卸载插件${D.plugin_id?`: ${D.plugin_id}`:""}`,D.operation==="update"&&`更新插件${D.plugin_id?`: ${D.plugin_id}`:""}`]})]}),e.jsxs("span",{className:"text-sm font-medium",children:[D.progress,"%"]})]}),e.jsx(wr,{value:D.progress,className:"h-2"}),e.jsx("div",{className:"text-xs text-muted-foreground",children:D.message}),D.operation==="fetch"&&D.total_plugins>0&&e.jsxs("div",{className:"text-xs text-muted-foreground text-center",children:["已加载 ",D.loaded_plugins," / ",D.total_plugins," 个插件"]})]})}),D&&D.stage==="error"&&D.error&&e.jsx(Ze,{className:"border-destructive bg-destructive/10",children:e.jsx(ys,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(_a,{className:"h-5 w-5 text-destructive"}),e.jsxs("div",{children:[e.jsx(ws,{className:"text-lg text-destructive",children:"加载失败"}),e.jsx(ct,{className:"text-destructive/80",children:D.error})]})]})})}),k?e.jsxs("div",{className:"flex items-center justify-center py-12",children:[e.jsx(kt,{className:"h-8 w-8 animate-spin text-muted-foreground"}),e.jsx("span",{className:"ml-3 text-muted-foreground",children:"加载插件列表中..."})]}):Y?e.jsx(Ze,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(_a,{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:Y}),e.jsx(N,{onClick:()=>window.location.reload(),children:"重新加载"})]})}):be.length===0?e.jsx(Ze,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(zt,{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||f!=="all"?"尝试调整搜索条件或筛选器":"暂无可用插件"})]})}):e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6",children:be.map(_=>e.jsxs(Ze,{className:"flex flex-col hover:shadow-lg transition-shadow h-full",children:[e.jsxs(ys,{children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsx(ws,{className:"text-xl",children:_.manifest?.name||_.id}),e.jsxs("div",{className:"flex flex-col gap-1",children:[_.manifest?.categories&&_.manifest.categories[0]&&e.jsx($e,{variant:"secondary",className:"text-xs whitespace-nowrap",children:vp[_.manifest.categories[0]]||_.manifest.categories[0]}),Se(_)]})]}),e.jsx(ct,{className:"line-clamp-2",children:_.manifest?.description||"无描述"})]}),e.jsx(Ts,{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(rl,{className:"h-4 w-4"}),e.jsx("span",{children:(M[_.id]?.downloads??_.downloads??0).toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ul,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:(M[_.id]?.rating??_.rating??0).toFixed(1)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[_.manifest?.keywords&&_.manifest.keywords.slice(0,3).map(me=>e.jsx($e,{variant:"outline",className:"text-xs",children:me},me)),_.manifest?.keywords&&_.manifest.keywords.length>3&&e.jsxs($e,{variant:"outline",className:"text-xs",children:["+",_.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",_.manifest?.version||"unknown"," · ",_.manifest?.author?.name||"Unknown"]}),_.manifest?.host_application&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{children:"支持:"}),e.jsxs("span",{className:"font-medium",children:[_.manifest.host_application.min_version,_.manifest.host_application.max_version?` - ${_.manifest.host_application.max_version}`:" - 最新版本"]})]})]})]})}),e.jsx(vg,{className:"pt-4",children:e.jsxs("div",{className:"flex items-center justify-end gap-2 w-full",children:[e.jsx(N,{variant:"outline",size:"sm",onClick:()=>c(_),children:"查看详情"}),_.installed?ye(_)?e.jsxs(N,{size:"sm",disabled:!R?.installed,title:R?.installed?void 0:"Git 未安装",onClick:()=>se(_),children:[e.jsx(Ct,{className:"h-4 w-4 mr-1"}),"更新"]}):e.jsxs(N,{variant:"destructive",size:"sm",disabled:!R?.installed,title:R?.installed?void 0:"Git 未安装",onClick:()=>E(_),children:[e.jsx(ts,{className:"h-4 w-4 mr-1"}),"卸载"]}):e.jsxs(N,{size:"sm",disabled:!R?.installed||D?.operation==="install"||$!==null&&!je(_),title:R?.installed?$!==null&&!je(_)?`不兼容当前版本 (需要 ${_.manifest?.host_application?.min_version||"未知"}${_.manifest?.host_application?.max_version?` - ${_.manifest.host_application.max_version}`:"+"},当前 ${$?.version})`:void 0:"Git 未安装",onClick:()=>K(_),children:[e.jsx(rl,{className:"h-4 w-4 mr-1"}),D?.operation==="install"&&D?.plugin_id===_.id?"安装中...":"安装"]})]})})]},_.id))}),e.jsx($s,{open:i!==null,onOpenChange:A,children:i&&i.manifest&&e.jsx(Hs,{className:"max-w-2xl max-h-[80vh] p-0 flex flex-col",children:e.jsx(ss,{className:"flex-1 overflow-auto",children:e.jsxs("div",{className:"p-6",children:[e.jsx(qs,{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(Gs,{className:"text-2xl",children:i.manifest.name}),e.jsxs(Is,{children:["作者: ",i.manifest.author?.name||"Unknown",i.manifest.author?.url&&e.jsx("a",{href:i.manifest.author.url,target:"_blank",rel:"noopener noreferrer",className:"ml-2 text-primary hover:underline",children:e.jsx(Xc,{className:"h-3 w-3 inline"})})]})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[i.manifest.categories&&i.manifest.categories[0]&&e.jsx($e,{variant:"secondary",children:vp[i.manifest.categories[0]]||i.manifest.categories[0]}),Se(i)]})]})}),e.jsxs("div",{className:"space-y-6",children:[e.jsx(O2,{pluginId:i.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",i.manifest?.version||"unknown"]}),i.installed&&i.installed_version&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["已安装: v",i.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:(M[i.id]?.downloads??i.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(Ul,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(M[i.id]?.rating??i.rating??0).toFixed(1)," (",M[i.id]?.rating_count??i.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:i.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:[i.manifest.host_application?.min_version||"未知",i.manifest.host_application?.max_version?` - ${i.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:i.manifest.keywords&&i.manifest.keywords.map(_=>e.jsx($e,{variant:"outline",children:_},_))})]}),i.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:i.detailed_description})]}),!i.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:i.manifest.description||"无描述"})]}),e.jsxs("div",{className:"space-y-2",children:[i.manifest.homepage_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"主页: "}),e.jsx("a",{href:i.manifest.homepage_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:i.manifest.homepage_url})]}),i.manifest.repository_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"仓库: "}),e.jsx("a",{href:i.manifest.repository_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:i.manifest.repository_url})]})]})]}),e.jsxs(at,{children:[i.manifest.homepage_url&&e.jsxs(N,{onClick:()=>window.open(i.manifest.homepage_url,"_blank"),children:[e.jsx(Xc,{className:"h-4 w-4 mr-2"}),"访问主页"]}),i.manifest.repository_url&&e.jsxs(N,{variant:"outline",onClick:()=>window.open(i.manifest.repository_url,"_blank"),children:[e.jsx(Xc,{className:"h-4 w-4 mr-2"}),"查看仓库"]})]})]})})})})]})})}const Gu=UN,Vu=BN,Fu=HN;function L2({field:n,value:i,onChange:c}){const[d,h]=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(b,{children:n.label}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]}),e.jsx(Qe,{checked:!!i,onCheckedChange:c,disabled:n.disabled})]});case"number":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:n.label}),e.jsx(ie,{type:"number",value:i??n.default,onChange:f=>c(parseFloat(f.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(b,{children:n.label}),e.jsx("span",{className:"text-sm text-muted-foreground",children:i??n.default})]}),e.jsx(wa,{value:[i??n.default],onValueChange:f=>c(f[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(b,{children:n.label}),e.jsxs(Be,{value:String(i??n.default),onValueChange:c,disabled:n.disabled,children:[e.jsx(Le,{children:e.jsx(He,{placeholder:n.placeholder??"请选择"})}),e.jsx(Ue,{children:n.choices?.map(f=>e.jsx(te,{value:String(f),children:String(f)},String(f)))})]}),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(b,{children:n.label}),e.jsx(Bs,{value:i??n.default,onChange:f=>c(f.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(b,{children:n.label}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{type:d?"text":"password",value:i??"",onChange:f=>c(f.target.value),placeholder:n.placeholder,disabled:n.disabled,className:"pr-10"}),e.jsx(N,{type:"button",variant:"ghost",size:"icon",className:"absolute right-0 top-0 h-full px-3",onClick:()=>h(!d),children:d?e.jsx(xr,{className:"h-4 w-4"}):e.jsx(Dt,{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(b,{children:n.label}),e.jsx(ie,{type:"text",value:i??n.default??"",onChange:f=>c(f.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 Np({section:n,config:i,onChange:c}){const[d,h]=u.useState(!n.collapsed),f=Object.entries(n.fields).filter(([,x])=>!x.hidden).sort(([,x],[,j])=>x.order-j.order);return e.jsx(Gu,{open:d,onOpenChange:h,children:e.jsxs(Ze,{children:[e.jsx(Vu,{asChild:!0,children:e.jsxs(ys,{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(Bl,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(ul,{className:"h-4 w-4 text-muted-foreground"}),e.jsx(ws,{className:"text-lg",children:n.title})]}),e.jsxs($e,{variant:"secondary",className:"text-xs",children:[f.length," 项"]})]}),n.description&&e.jsx(ct,{className:"ml-6",children:n.description})]})}),e.jsx(Fu,{children:e.jsx(Ts,{className:"space-y-4 pt-0",children:f.map(([x,j])=>e.jsx(L2,{field:j,value:i[n.name]?.[x],onChange:p=>c(n.name,x,p),sectionName:n.name},x))})})]})})}function U2({plugin:n,onBack:i}){const{toast:c}=Vs(),[d,h]=u.useState(null),[f,x]=u.useState({}),[j,p]=u.useState({}),[w,v]=u.useState(!0),[y,S]=u.useState(!1),[k,O]=u.useState(!1),[Y,L]=u.useState(!1),R=u.useCallback(async()=>{v(!0);try{const[M,ne]=await Promise.all([_2(n.id),S2(n.id)]);h(M),x(ne),p(JSON.parse(JSON.stringify(ne)))}catch(M){c({title:"加载配置失败",description:M instanceof Error?M.message:"未知错误",variant:"destructive"})}finally{v(!1)}},[n.id,c]);u.useEffect(()=>{R()},[R]),u.useEffect(()=>{O(JSON.stringify(f)!==JSON.stringify(j))},[f,j]);const H=(M,ne,fe)=>{x(_e=>({..._e,[M]:{..._e[M]||{},[ne]:fe}}))},D=async()=>{S(!0);try{await C2(n.id,f),p(JSON.parse(JSON.stringify(f))),c({title:"配置已保存",description:"更改将在插件重新加载后生效"})}catch(M){c({title:"保存失败",description:M instanceof Error?M.message:"未知错误",variant:"destructive"})}finally{S(!1)}},C=async()=>{try{await k2(n.id),c({title:"配置已重置",description:"下次加载插件时将使用默认配置"}),L(!1),R()}catch(M){c({title:"重置失败",description:M instanceof Error?M.message:"未知错误",variant:"destructive"})}},$=async()=>{try{const M=await T2(n.id);c({title:M.message,description:M.note}),R()}catch(M){c({title:"切换状态失败",description:M instanceof Error?M.message:"未知错误",variant:"destructive"})}};if(w)return e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx(kt,{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(Sa,{className:"h-12 w-12 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"无法加载配置"}),e.jsxs(N,{onClick:i,variant:"outline",children:[e.jsx(ii,{className:"h-4 w-4 mr-2"}),"返回"]})]});const G=Object.values(d.sections).sort((M,ne)=>M.order-ne.order),T=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(N,{variant:"ghost",size:"icon",onClick:i,children:e.jsx(ii,{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($e,{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(N,{variant:"outline",size:"sm",onClick:$,children:[e.jsx(br,{className:"h-4 w-4 mr-2"}),T?"禁用":"启用"]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>L(!0),children:[e.jsx(Zc,{className:"h-4 w-4 mr-2"}),"重置"]}),e.jsxs(N,{size:"sm",onClick:D,disabled:!k||y,children:[y?e.jsx(kt,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(yr,{className:"h-4 w-4 mr-2"}),"保存"]})]})]}),k&&e.jsx(Ze,{className:"border-orange-200 bg-orange-50 dark:bg-orange-950/20 dark:border-orange-900",children:e.jsx(Ts,{className:"py-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(La,{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(Ca,{defaultValue:d.layout.tabs[0]?.id,children:[e.jsx(pa,{children:d.layout.tabs.map(M=>e.jsxs(ns,{value:M.id,children:[M.title,M.badge&&e.jsx($e,{variant:"secondary",className:"ml-2 text-xs",children:M.badge})]},M.id))}),d.layout.tabs.map(M=>e.jsx(Es,{value:M.id,className:"space-y-4 mt-4",children:M.sections.map(ne=>{const fe=d.sections[ne];return fe?e.jsx(Np,{section:fe,config:f,onChange:H},ne):null})},M.id))]}):e.jsx("div",{className:"space-y-4",children:G.map(M=>e.jsx(Np,{section:M,config:f,onChange:H},M.name))}),e.jsx($s,{open:Y,onOpenChange:L,children:e.jsxs(Hs,{children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"确认重置配置"}),e.jsx(Is,{children:"这将删除当前配置文件,下次加载插件时将使用默认配置。此操作不可撤销。"})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>L(!1),children:"取消"}),e.jsx(N,{variant:"destructive",onClick:C,children:"确认重置"})]})]})})]})}function B2(){const{toast:n}=Vs(),[i,c]=u.useState([]),[d,h]=u.useState(!0),[f,x]=u.useState(""),[j,p]=u.useState(null),w=async()=>{h(!0);try{const k=await dr();c(k)}catch(k){n({title:"加载插件列表失败",description:k instanceof Error?k.message:"未知错误",variant:"destructive"})}finally{h(!1)}};u.useEffect(()=>{w()},[]);const v=i.filter(k=>{const O=f.toLowerCase();return k.id.toLowerCase().includes(O)||k.manifest.name.toLowerCase().includes(O)||k.manifest.description?.toLowerCase().includes(O)}),y=i.length,S=0;return j?e.jsx(ss,{className:"h-full",children:e.jsx("div",{className:"p-4 sm:p-6",children:e.jsx(U2,{plugin:j,onBack:()=>p(null)})})}):e.jsx(ss,{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(N,{variant:"outline",size:"sm",onClick:w,children:[e.jsx(Ct,{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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"已安装插件"}),e.jsx(dn,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-2xl font-bold",children:i.length}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:d?"正在加载...":"个插件"})]})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"已启用"}),e.jsx(fa,{className:"h-4 w-4 text-green-600"})]}),e.jsxs(Ts,{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(Ze,{children:[e.jsxs(ys,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ws,{className:"text-sm font-medium",children:"已禁用"}),e.jsx(Sa,{className:"h-4 w-4 text-orange-600"})]}),e.jsxs(Ts,{children:[e.jsx("div",{className:"text-2xl font-bold",children:S}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"未激活的插件"})]})]})]}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索插件...",value:f,onChange:k=>x(k.target.value),className:"pl-9"})]}),e.jsxs(Ze,{children:[e.jsxs(ys,{children:[e.jsx(ws,{children:"已安装的插件"}),e.jsx(ct,{children:"点击插件查看和编辑配置"})]}),e.jsx(Ts,{children:d?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx(kt,{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(dn,{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:f?"没有找到匹配的插件":"暂无已安装的插件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:f?"尝试其他搜索关键词":"前往插件市场安装插件"})]})]}):e.jsx("div",{className:"space-y-2",children:v.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:()=>p(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(dn,{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($e,{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(N,{variant:"ghost",size:"sm",children:e.jsx(oi,{className:"h-4 w-4"})}),e.jsx(ul,{className:"h-4 w-4 text-muted-foreground"})]})]},k.id))})})]})]})})}function H2(){const n=ja(),{toast:i}=Vs(),[c,d]=u.useState([]),[h,f]=u.useState(!0),[x,j]=u.useState(null),[p,w]=u.useState(null),[v,y]=u.useState(!1),[S,k]=u.useState(!1),[O,Y]=u.useState({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),L=u.useCallback(async()=>{try{f(!0),j(null);const T=localStorage.getItem("access-token"),M=await fetch("/api/webui/plugins/mirrors",{headers:{Authorization:`Bearer ${T}`}});if(!M.ok)throw new Error("获取镜像源列表失败");const ne=await M.json();d(ne.mirrors||[])}catch(T){const M=T instanceof Error?T.message:"加载镜像源失败";j(M),i({title:"加载失败",description:M,variant:"destructive"})}finally{f(!1)}},[i]);u.useEffect(()=>{L()},[L]);const R=async()=>{try{const T=localStorage.getItem("access-token"),M=await fetch("/api/webui/plugins/mirrors",{method:"POST",headers:{Authorization:`Bearer ${T}`,"Content-Type":"application/json"},body:JSON.stringify(O)});if(!M.ok){const ne=await M.json();throw new Error(ne.detail||"添加镜像源失败")}i({title:"添加成功",description:"镜像源已添加"}),y(!1),Y({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),L()}catch(T){i({title:"添加失败",description:T instanceof Error?T.message:"未知错误",variant:"destructive"})}},H=async()=>{if(p)try{const T=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${p.id}`,{method:"PUT",headers:{Authorization:`Bearer ${T}`,"Content-Type":"application/json"},body:JSON.stringify({name:O.name,raw_prefix:O.raw_prefix,clone_prefix:O.clone_prefix,enabled:O.enabled,priority:O.priority})})).ok)throw new Error("更新镜像源失败");i({title:"更新成功",description:"镜像源已更新"}),k(!1),w(null),L()}catch(T){i({title:"更新失败",description:T instanceof Error?T.message:"未知错误",variant:"destructive"})}},D=async T=>{if(confirm("确定要删除这个镜像源吗?"))try{const M=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T}`,{method:"DELETE",headers:{Authorization:`Bearer ${M}`}})).ok)throw new Error("删除镜像源失败");i({title:"删除成功",description:"镜像源已删除"}),L()}catch(M){i({title:"删除失败",description:M instanceof Error?M.message:"未知错误",variant:"destructive"})}},C=async T=>{try{const M=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T.id}`,{method:"PUT",headers:{Authorization:`Bearer ${M}`,"Content-Type":"application/json"},body:JSON.stringify({enabled:!T.enabled})})).ok)throw new Error("更新状态失败");L()}catch(M){i({title:"更新失败",description:M instanceof Error?M.message:"未知错误",variant:"destructive"})}},$=T=>{w(T),Y({id:T.id,name:T.name,raw_prefix:T.raw_prefix,clone_prefix:T.clone_prefix,enabled:T.enabled,priority:T.priority}),k(!0)},G=async(T,M)=>{const ne=M==="up"?T.priority-1:T.priority+1;if(!(ne<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:ne})})).ok)throw new Error("更新优先级失败");L()}catch(fe){i({title:"更新失败",description:fe instanceof Error?fe.message:"未知错误",variant:"destructive"})}};return e.jsx(ss,{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(N,{variant:"ghost",size:"icon",onClick:()=>n({to:"/plugins"}),children:e.jsx(ii,{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(N,{onClick:()=>y(!0),children:[e.jsx(ot,{className:"h-4 w-4 mr-2"}),"添加镜像源"]})]}),h?e.jsx(Ze,{className:"p-6",children:e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(kt,{className:"h-8 w-8 animate-spin text-primary"})})}):x?e.jsx(Ze,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(_a,{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:x}),e.jsx(N,{onClick:L,children:"重新加载"})]})}):e.jsxs(Ze,{children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(hn,{children:[e.jsx(xn,{children:e.jsxs(dt,{children:[e.jsx(Ie,{children:"状态"}),e.jsx(Ie,{children:"名称"}),e.jsx(Ie,{children:"ID"}),e.jsx(Ie,{children:"优先级"}),e.jsx(Ie,{className:"text-right",children:"操作"})]})}),e.jsx(fn,{children:c.map(T=>e.jsxs(dt,{children:[e.jsx(Fe,{children:e.jsx(Qe,{checked:T.enabled,onCheckedChange:()=>C(T)})}),e.jsx(Fe,{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(Fe,{children:e.jsx($e,{variant:"outline",children:T.id})}),e.jsx(Fe,{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(N,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>G(T,"up"),disabled:T.priority===1,children:e.jsx(pr,{className:"h-3 w-3"})}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>G(T,"down"),children:e.jsx(Bl,{className:"h-3 w-3"})})]})]})}),e.jsx(Fe,{className:"text-right",children:e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(N,{variant:"ghost",size:"icon",onClick:()=>$(T),children:e.jsx(on,{className:"h-4 w-4"})}),e.jsx(N,{variant:"ghost",size:"icon",onClick:()=>D(T.id),children:e.jsx(ts,{className:"h-4 w-4 text-destructive"})})]})})]},T.id))})]})}),e.jsx("div",{className:"md:hidden p-4 space-y-4",children:c.map(T=>e.jsx(Ze,{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($e,{variant:"default",className:"text-xs",children:"启用"})]}),e.jsx($e,{variant:"outline",className:"mt-1 text-xs",children:T.id})]}),e.jsx(Qe,{checked:T.enabled,onCheckedChange:()=>C(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(N,{variant:"outline",size:"sm",className:"flex-1",onClick:()=>$(T),children:[e.jsx(on,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>G(T,"up"),disabled:T.priority===1,children:e.jsx(pr,{className:"h-4 w-4"})}),e.jsx(N,{variant:"outline",size:"sm",onClick:()=>G(T,"down"),children:e.jsx(Bl,{className:"h-4 w-4"})}),e.jsx(N,{variant:"destructive",size:"sm",onClick:()=>D(T.id),children:e.jsx(ts,{className:"h-4 w-4"})})]})]})},T.id))})]}),e.jsx($s,{open:v,onOpenChange:y,children:e.jsxs(Hs,{className:"max-w-lg",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"添加镜像源"}),e.jsx(Is,{children:"添加新的 Git 镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-id",children:"镜像源 ID *"}),e.jsx(ie,{id:"add-id",placeholder:"例如: my-mirror",value:O.id,onChange:T=>Y({...O,id:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-name",children:"名称 *"}),e.jsx(ie,{id:"add-name",placeholder:"例如: 我的镜像源",value:O.name,onChange:T=>Y({...O,name:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-raw",children:"Raw 文件前缀 *"}),e.jsx(ie,{id:"add-raw",placeholder:"https://example.com/raw",value:O.raw_prefix,onChange:T=>Y({...O,raw_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-clone",children:"克隆前缀 *"}),e.jsx(ie,{id:"add-clone",placeholder:"https://example.com/clone",value:O.clone_prefix,onChange:T=>Y({...O,clone_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"add-priority",children:"优先级"}),e.jsx(ie,{id:"add-priority",type:"number",min:"1",value:O.priority,onChange:T=>Y({...O,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(Qe,{id:"add-enabled",checked:O.enabled,onCheckedChange:T=>Y({...O,enabled:T})}),e.jsx(b,{htmlFor:"add-enabled",children:"启用此镜像源"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(N,{onClick:R,children:"添加"})]})]})}),e.jsx($s,{open:S,onOpenChange:k,children:e.jsxs(Hs,{className:"max-w-lg",children:[e.jsxs(qs,{children:[e.jsx(Gs,{children:"编辑镜像源"}),e.jsx(Is,{children:"修改镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"镜像源 ID"}),e.jsx(ie,{value:O.id,disabled:!0})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-name",children:"名称 *"}),e.jsx(ie,{id:"edit-name",value:O.name,onChange:T=>Y({...O,name:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-raw",children:"Raw 文件前缀 *"}),e.jsx(ie,{id:"edit-raw",value:O.raw_prefix,onChange:T=>Y({...O,raw_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-clone",children:"克隆前缀 *"}),e.jsx(ie,{id:"edit-clone",value:O.clone_prefix,onChange:T=>Y({...O,clone_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{htmlFor:"edit-priority",children:"优先级"}),e.jsx(ie,{id:"edit-priority",type:"number",min:"1",value:O.priority,onChange:T=>Y({...O,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(Qe,{id:"edit-enabled",checked:O.enabled,onCheckedChange:T=>Y({...O,enabled:T})}),e.jsx(b,{htmlFor:"edit-enabled",children:"启用此镜像源"})]})]}),e.jsxs(at,{children:[e.jsx(N,{variant:"outline",onClick:()=>k(!1),children:"取消"}),e.jsx(N,{onClick:H,children:"保存"})]})]})})]})})}const ur=u.forwardRef(({className:n,...i},c)=>e.jsx(Hp,{ref:c,className:X("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",n),...i}));ur.displayName=Hp.displayName;const q2=u.forwardRef(({className:n,...i},c)=>e.jsx(qp,{ref:c,className:X("aspect-square h-full w-full",n),...i}));q2.displayName=qp.displayName;const mr=u.forwardRef(({className:n,...i},c)=>e.jsx(Gp,{ref:c,className:X("flex h-full w-full items-center justify-center rounded-full bg-muted",n),...i}));mr.displayName=Gp.displayName;function G2(){return"webui_"+Math.random().toString(36).substr(2,9)+"_"+Date.now().toString(36)}function V2(){const n="maibot_webui_user_id";let i=localStorage.getItem(n);return i||(i=G2(),localStorage.setItem(n,i)),i}function F2(){return localStorage.getItem("maibot_webui_user_name")||"WebUI用户"}function $2(n){localStorage.setItem("maibot_webui_user_name",n)}const Vg="maibot_webui_virtual_tabs";function Q2(){try{const n=localStorage.getItem(Vg);if(n)return JSON.parse(n)}catch(n){console.error("[Chat] 加载虚拟标签页失败:",n)}return[]}function bp(n){try{localStorage.setItem(Vg,JSON.stringify(n))}catch(i){console.error("[Chat] 保存虚拟标签页失败:",i)}}function Y2(){const n={id:"webui-default",type:"webui",label:"WebUI",messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}},i=()=>{const Re=Q2().map(ze=>{const Ye=ze.virtualConfig;return!Ye.groupId&&Ye.platform&&Ye.userId&&(Ye.groupId=`webui_virtual_group_${Ye.platform}_${Ye.userId}`),{id:ze.id,type:"virtual",label:ze.label,virtualConfig:Ye,messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}}});return[n,...Re]},[c,d]=u.useState(i),[h,f]=u.useState("webui-default"),x=c.find(U=>U.id===h)||c[0],[j,p]=u.useState(""),[w,v]=u.useState(!1),[y,S]=u.useState(!0),[k,O]=u.useState(F2()),[Y,L]=u.useState(!1),[R,H]=u.useState(""),[D,C]=u.useState(!1),[$,G]=u.useState([]),[T,M]=u.useState([]),[ne,fe]=u.useState(!1),[_e,Se]=u.useState(!1),[je,ye]=u.useState(""),[be,A]=u.useState({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),K=u.useRef(V2()),E=u.useRef(new Map),se=u.useRef(null),_=u.useRef(new Map),me=u.useRef(0),re=u.useRef(new Map),{toast:le}=Vs(),pe=U=>(me.current+=1,`${U}-${Date.now()}-${me.current}-${Math.random().toString(36).substr(2,9)}`),Ne=u.useCallback((U,Re)=>{d(ze=>ze.map(Ye=>Ye.id===U?{...Ye,...Re}:Ye))},[]),he=u.useCallback((U,Re)=>{d(ze=>ze.map(Ye=>Ye.id===U?{...Ye,messages:[...Ye.messages,Re]}:Ye))},[]),Q=u.useCallback(()=>{se.current?.scrollIntoView({behavior:"smooth"})},[]);u.useEffect(()=>{Q()},[x?.messages,Q]);const P=u.useCallback(async()=>{fe(!0);try{const U=await Te("/api/chat/platforms");if(console.log("[Chat] 平台列表响应:",U.status,U.headers.get("content-type")),U.ok){const Re=U.headers.get("content-type");if(Re&&Re.includes("application/json")){const ze=await U.json();console.log("[Chat] 平台列表数据:",ze),G(ze.platforms||[])}else{const ze=await U.text();console.error("[Chat] 获取平台列表失败: 非 JSON 响应:",ze.substring(0,200)),le({title:"连接失败",description:"无法连接到后端服务,请确保 MaiBot 已启动",variant:"destructive"})}}else console.error("[Chat] 获取平台列表失败: HTTP",U.status),le({title:"获取平台失败",description:`服务器返回错误: ${U.status}`,variant:"destructive"})}catch(U){console.error("[Chat] 获取平台列表失败:",U),le({title:"网络错误",description:"无法连接到后端服务",variant:"destructive"})}finally{fe(!1)}},[le]),q=u.useCallback(async(U,Re)=>{Se(!0);try{const ze=new URLSearchParams;U&&ze.append("platform",U),Re&&ze.append("search",Re),ze.append("limit","50");const Ye=await Te(`/api/chat/persons?${ze.toString()}`);if(Ye.ok){const zs=Ye.headers.get("content-type");if(zs&&zs.includes("application/json")){const We=await Ye.json();M(We.persons||[])}else console.error("[Chat] 获取用户列表失败: 后端返回非 JSON 响应")}}catch(ze){console.error("[Chat] 获取用户列表失败:",ze)}finally{Se(!1)}},[]);u.useEffect(()=>{be.platform&&q(be.platform,je)},[be.platform,je,q]);const W=u.useCallback(async(U,Re)=>{S(!0);try{const ze=new URLSearchParams;ze.append("user_id",K.current),ze.append("limit","50"),Re&&ze.append("group_id",Re);const Ye=`/api/chat/history?${ze.toString()}`;console.log("[Chat] 正在加载历史消息:",Ye);const zs=await Te(Ye);if(zs.ok){const We=await zs.text();try{const nt=JSON.parse(We);if(nt.messages&&nt.messages.length>0){const vs=nt.messages.map(ve=>({id:ve.id,type:ve.type,content:ve.content,timestamp:ve.timestamp,sender:{name:ve.sender_name||(ve.is_bot?"麦麦":"WebUI用户"),user_id:ve.user_id,is_bot:ve.is_bot}}));Ne(U,{messages:vs});const ke=re.current.get(U)||new Set;vs.forEach(ve=>{if(ve.type==="bot"){const is=`bot-${ve.content}-${Math.floor(ve.timestamp*1e3)}`;ke.add(is)}}),re.current.set(U,ke)}}catch(nt){console.error("[Chat] JSON 解析失败:",nt)}}}catch(ze){console.error("[Chat] 加载历史消息失败:",ze)}finally{S(!1)}},[Ne]),Ce=u.useCallback((U,Re,ze)=>{const Ye=E.current.get(U);if(Ye?.readyState===WebSocket.OPEN||Ye?.readyState===WebSocket.CONNECTING){console.log(`[Tab ${U}] WebSocket 已存在,跳过连接`);return}v(!0);const zs=window.location.protocol==="https:"?"wss:":"ws:",We=new URLSearchParams;Re==="virtual"&&ze?(We.append("user_id",ze.userId),We.append("user_name",ze.userName),We.append("platform",ze.platform),We.append("person_id",ze.personId),We.append("group_name",ze.groupName||"WebUI虚拟群聊"),ze.groupId&&We.append("group_id",ze.groupId)):(We.append("user_id",K.current),We.append("user_name",k));const nt=`${zs}//${window.location.host}/api/chat/ws?${We.toString()}`;console.log(`[Tab ${U}] 正在连接 WebSocket:`,nt);try{const vs=new WebSocket(nt);E.current.set(U,vs),vs.onopen=()=>{Ne(U,{isConnected:!0}),v(!1),console.log(`[Tab ${U}] WebSocket 已连接`)},vs.onmessage=ke=>{try{const ve=JSON.parse(ke.data);switch(ve.type){case"session_info":Ne(U,{sessionInfo:{session_id:ve.session_id,user_id:ve.user_id,user_name:ve.user_name,bot_name:ve.bot_name}});break;case"system":he(U,{id:pe("sys"),type:"system",content:ve.content||"",timestamp:ve.timestamp||Date.now()/1e3});break;case"user_message":{const is=ve.sender?.user_id,_s=Re==="virtual"&&ze?ze.userId:K.current;if(is===_s)break;he(U,{id:ve.message_id||pe("user"),type:"user",content:ve.content||"",timestamp:ve.timestamp||Date.now()/1e3,sender:ve.sender});break}case"bot_message":{Ne(U,{isTyping:!1});const is=re.current.get(U)||new Set,_s=`bot-${ve.content}-${Math.floor((ve.timestamp||0)*1e3)}`;if(is.has(_s))break;if(is.add(_s),re.current.set(U,is),is.size>100){const At=is.values().next().value;At&&is.delete(At)}d(At=>At.map(Ps=>{if(Ps.id!==U)return Ps;const Ys=Ps.messages.filter(Et=>Et.type!=="thinking");return{...Ps,messages:[...Ys,{id:pe("bot"),type:"bot",content:ve.content||"",timestamp:ve.timestamp||Date.now()/1e3,sender:ve.sender}]}}));break}case"typing":Ne(U,{isTyping:ve.is_typing||!1});break;case"error":d(is=>is.map(_s=>{if(_s.id!==U)return _s;const At=_s.messages.filter(Ps=>Ps.type!=="thinking");return{..._s,messages:[...At,{id:pe("error"),type:"error",content:ve.content||"发生错误",timestamp:ve.timestamp||Date.now()/1e3}]}})),le({title:"错误",description:ve.content,variant:"destructive"});break;case"pong":break;case"history":{const is=ve.messages||[];if(is.length>0){const _s=re.current.get(U)||new Set,At=is.map(Ps=>{const Ys=Ps.is_bot||!1,Et=Ps.id||pe(Ys?"bot":"user"),Rt=`${Ys?"bot":"user"}-${Ps.content}-${Math.floor(Ps.timestamp*1e3)}`;return _s.add(Rt),{id:Et,type:Ys?"bot":"user",content:Ps.content,timestamp:Ps.timestamp,sender:{name:Ps.sender_name||(Ys?"麦麦":"用户"),user_id:Ps.sender_id,is_bot:Ys}}});re.current.set(U,_s),Ne(U,{messages:At}),console.log(`[Tab ${U}] 已加载 ${At.length} 条历史消息`)}break}default:console.log("未知消息类型:",ve.type)}}catch(ve){console.error("解析消息失败:",ve)}},vs.onclose=()=>{Ne(U,{isConnected:!1}),v(!1),E.current.delete(U),console.log(`[Tab ${U}] WebSocket 已断开`);const ke=_.current.get(U);ke&&clearTimeout(ke);const ve=window.setTimeout(()=>{if(!Me.current){const is=c.find(_s=>_s.id===U);is&&Ce(U,is.type,is.virtualConfig)}},5e3);_.current.set(U,ve)},vs.onerror=ke=>{console.error(`[Tab ${U}] WebSocket 错误:`,ke),v(!1)}}catch(vs){console.error(`[Tab ${U}] 创建 WebSocket 失败:`,vs),v(!1)}},[k,Ne,he,le,c]),Me=u.useRef(!1);u.useEffect(()=>{Me.current=!1;const U=E.current,Re=_.current,ze=re.current;W("webui-default");const Ye=setTimeout(()=>{Me.current||(Ce("webui-default","webui"),c.forEach(We=>{We.type==="virtual"&&We.virtualConfig&&(ze.set(We.id,new Set),setTimeout(()=>{Me.current||Ce(We.id,"virtual",We.virtualConfig)},200))}))},100),zs=setInterval(()=>{U.forEach(We=>{We.readyState===WebSocket.OPEN&&We.send(JSON.stringify({type:"ping"}))})},3e4);return()=>{Me.current=!0,clearTimeout(Ye),clearInterval(zs),Re.forEach(We=>{clearTimeout(We)}),Re.clear(),U.forEach(We=>{We.close()}),U.clear()}},[]);const ce=u.useCallback(()=>{const U=E.current.get(h);if(!j.trim()||!U||U.readyState!==WebSocket.OPEN)return;const Re=x?.type==="virtual"&&x.virtualConfig?.userName||k,ze=j.trim(),Ye=Date.now()/1e3;U.send(JSON.stringify({type:"message",content:ze,user_name:Re}));const zs={id:pe("user"),type:"user",content:ze,timestamp:Ye,sender:{name:Re,is_bot:!1}};he(h,zs);const We={id:pe("thinking"),type:"thinking",content:"",timestamp:Ye+.001,sender:{name:x?.sessionInfo.bot_name||"麦麦",is_bot:!0}};he(h,We),p("")},[j,k,h,x,he]),De=U=>{U.key==="Enter"&&!U.shiftKey&&(U.preventDefault(),ce())},Fs=()=>{H(k),L(!0)},Qs=()=>{const U=R.trim()||"WebUI用户";O(U),$2(U),L(!1);const Re=E.current.get(h);Re?.readyState===WebSocket.OPEN&&Re.send(JSON.stringify({type:"update_nickname",user_name:U}))},ue=()=>{H(""),L(!1)},Ee=U=>new Date(U*1e3).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"}),as=()=>{const U=E.current.get(h);U&&(U.close(),E.current.delete(h)),Ce(h,x?.type||"webui",x?.virtualConfig)},Ke=()=>{A({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),ye(""),P(),C(!0)},lt=()=>{if(!be.platform||!be.personId){le({title:"配置不完整",description:"请选择平台和用户",variant:"destructive"});return}const U=`webui_virtual_group_${be.platform}_${be.userId}`,Re=`virtual-${be.platform}-${be.userId}-${Date.now()}`,ze=be.userName||be.userId,Ye={id:Re,type:"virtual",label:ze,virtualConfig:{...be,groupId:U},messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}};d(zs=>{const We=[...zs,Ye],nt=We.filter(vs=>vs.type==="virtual"&&vs.virtualConfig).map(vs=>({id:vs.id,label:vs.label,virtualConfig:vs.virtualConfig,createdAt:Date.now()}));return bp(nt),We}),f(Re),C(!1),re.current.set(Re,new Set),setTimeout(()=>{Ce(Re,"virtual",be)},100),le({title:"虚拟身份标签页",description:`已创建 ${ze} 的对话`})},Ot=(U,Re)=>{if(Re?.stopPropagation(),U==="webui-default")return;const ze=E.current.get(U);ze&&(ze.close(),E.current.delete(U));const Ye=_.current.get(U);Ye&&(clearTimeout(Ye),_.current.delete(U)),re.current.delete(U),d(zs=>{const We=zs.filter(vs=>vs.id!==U),nt=We.filter(vs=>vs.type==="virtual"&&vs.virtualConfig).map(vs=>({id:vs.id,label:vs.label,virtualConfig:vs.virtualConfig,createdAt:Date.now()}));return bp(nt),We}),h===U&&f("webui-default")},bt=U=>{f(U)},Pe=U=>{A(Re=>({...Re,personId:U.person_id,userId:U.user_id,userName:U.nickname||U.person_name}))};return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsx($s,{open:D,onOpenChange:C,children:e.jsxs(Hs,{className:"sm:max-w-[500px] max-h-[85vh] overflow-hidden flex flex-col",children:[e.jsxs(qs,{children:[e.jsxs(Gs,{className:"flex items-center gap-2",children:[e.jsx(wu,{className:"h-5 w-5"}),"新建虚拟身份对话"]}),e.jsx(Is,{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(b,{className:"flex items-center gap-2",children:[e.jsx(Lu,{className:"h-4 w-4"}),"选择平台"]}),e.jsxs(Be,{value:be.platform,onValueChange:U=>{A(Re=>({...Re,platform:U,personId:"",userId:"",userName:""})),M([])},children:[e.jsx(Le,{disabled:ne,children:e.jsx(He,{placeholder:ne?"加载中...":"选择平台"})}),e.jsx(Ue,{children:$.map(U=>e.jsxs(te,{value:U.platform,children:[U.platform," (",U.count," 人)"]},U.platform))})]})]}),be.platform&&e.jsxs("div",{className:"space-y-2 flex-1 overflow-hidden flex flex-col",children:[e.jsxs(b,{className:"flex items-center gap-2",children:[e.jsx(Uu,{className:"h-4 w-4"}),"选择用户"]}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索用户名...",value:je,onChange:U=>ye(U.target.value),className:"pl-9"})]}),e.jsx(ss,{className:"h-[250px] border rounded-md",children:e.jsx("div",{className:"p-2",children:_e?e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(kt,{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(Uu,{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(U=>e.jsxs("button",{onClick:()=>Pe(U),className:X("w-full flex items-center gap-3 p-2 rounded-md text-left transition-colors",be.personId===U.person_id?"bg-primary text-primary-foreground":"hover:bg-muted"),children:[e.jsx(ur,{className:"h-8 w-8 shrink-0",children:e.jsx(mr,{className:X("text-xs",be.personId===U.person_id?"bg-primary-foreground/20":"bg-muted"),children:(U.nickname||U.person_name||"?").charAt(0)})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-medium truncate",children:U.nickname||U.person_name}),e.jsxs("div",{className:X("text-xs truncate",be.personId===U.person_id?"text-primary-foreground/70":"text-muted-foreground"),children:["ID: ",U.user_id,U.is_known&&" · 已认识"]})]})]},U.person_id))})})})]}),be.personId&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(b,{children:"虚拟群名(可选)"}),e.jsx(ie,{placeholder:"WebUI虚拟群聊",value:be.groupName,onChange:U=>A(Re=>({...Re,groupName:U.target.value}))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦会认为这是一个名为此名称的群聊"})]})]}),e.jsxs(at,{className:"gap-2 sm:gap-0",children:[e.jsx(N,{variant:"outline",onClick:()=>C(!1),children:"取消"}),e.jsx(N,{onClick:lt,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:[c.map(U=>e.jsxs("button",{onClick:()=>bt(U.id),className:X("flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm whitespace-nowrap transition-colors","hover:bg-muted",h===U.id?"bg-background shadow-sm border":"text-muted-foreground"),children:[U.type==="webui"?e.jsx(un,{className:"h-3.5 w-3.5"}):e.jsx(wu,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"max-w-[100px] truncate",children:U.label}),e.jsx("span",{className:X("w-1.5 h-1.5 rounded-full",U.isConnected?"bg-green-500":"bg-muted-foreground/50")}),U.id!=="webui-default"&&e.jsx("button",{onClick:Re=>Ot(U.id,Re),className:"ml-0.5 p-0.5 rounded hover:bg-muted-foreground/20",children:e.jsx(dl,{className:"h-3 w-3"})})]},U.id)),e.jsx("button",{onClick:Ke,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(ot,{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(ur,{className:"h-8 w-8 sm:h-10 sm:w-10 shrink-0",children:e.jsx(mr,{className:"bg-primary/10 text-primary",children:e.jsx(cr,{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:x?.sessionInfo.bot_name||"麦麦"}),e.jsx("div",{className:"flex items-center gap-1.5 text-xs text-muted-foreground",children:x?.isConnected?e.jsxs(e.Fragment,{children:[e.jsx(Rb,{className:"h-3 w-3 text-green-500"}),e.jsx("span",{className:"text-green-600 dark:text-green-400",children:"已连接"})]}):w?e.jsxs(e.Fragment,{children:[e.jsx(kt,{className:"h-3 w-3 animate-spin"}),e.jsx("span",{children:"连接中..."})]}):e.jsxs(e.Fragment,{children:[e.jsx(Lb,{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(kt,{className:"h-4 w-4 animate-spin text-muted-foreground"}),e.jsx(N,{variant:"ghost",size:"icon",className:"h-8 w-8",onClick:as,disabled:w,title:"重新连接",children:e.jsx(Ct,{className:X("h-4 w-4",w&&"animate-spin")})})]})]}),e.jsx("div",{className:"hidden sm:flex items-center gap-2 mt-2 text-sm text-muted-foreground",children:x?.type==="virtual"&&x.virtualConfig?e.jsxs(e.Fragment,{children:[e.jsx(wu,{className:"h-3 w-3 text-primary"}),e.jsx("span",{children:"虚拟身份:"}),e.jsx("span",{className:"font-medium text-primary",children:x.virtualConfig.userName}),e.jsxs("span",{className:"text-xs",children:["(",x.virtualConfig.platform,")"]}),x.virtualConfig.groupName&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"mx-1",children:"·"}),e.jsxs("span",{className:"text-xs",children:["群:",x.virtualConfig.groupName]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx(Wc,{className:"h-3 w-3"}),e.jsx("span",{children:"当前身份:"}),Y?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{value:R,onChange:U=>H(U.target.value),onKeyDown:U=>{U.key==="Enter"&&Qs(),U.key==="Escape"&&ue()},className:"h-7 w-32",placeholder:"输入昵称",autoFocus:!0}),e.jsx(N,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:Qs,children:"保存"}),e.jsx(N,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:ue,children:"取消"})]}):e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"font-medium text-foreground",children:k}),e.jsx(N,{size:"sm",variant:"ghost",className:"h-6 w-6 p-0",onClick:Fs,title:"修改昵称",children:e.jsx(Ub,{className:"h-3 w-3"})})]})]})})]})}),e.jsx("div",{className:"flex-1 overflow-hidden",children:e.jsx(ss,{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:[x?.messages.length===0&&!y&&e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-muted-foreground",children:[e.jsx(cr,{className:"h-12 w-12 mb-4 opacity-50"}),e.jsxs("p",{className:"text-sm",children:["开始与 ",x?.sessionInfo.bot_name||"麦麦"," 对话吧!"]})]}),x?.messages.map(U=>e.jsxs("div",{className:X("flex gap-2 sm:gap-3",U.type==="user"&&"flex-row-reverse",U.type==="system"&&"justify-center",U.type==="error"&&"justify-center"),children:[U.type==="system"&&e.jsx("div",{className:"text-xs text-muted-foreground bg-muted/50 px-3 py-1 rounded-full max-w-[90%]",children:U.content}),U.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:U.content}),U.type==="thinking"&&e.jsxs(e.Fragment,{children:[e.jsx(ur,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(mr,{className:"bg-primary/10 text-primary",children:e.jsx(cr,{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:U.sender?.name||x?.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:"思考中..."})]})})]})]}),(U.type==="user"||U.type==="bot")&&e.jsxs(e.Fragment,{children:[e.jsx(ur,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(mr,{className:X("text-xs",U.type==="bot"?"bg-primary/10 text-primary":"bg-secondary text-secondary-foreground"),children:U.type==="bot"?e.jsx(cr,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"}):e.jsx(Wc,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"})})}),e.jsxs("div",{className:X("flex flex-col gap-1 max-w-[75%] sm:max-w-[70%]",U.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:U.sender?.name||(U.type==="bot"?x?.sessionInfo.bot_name:k)}),e.jsx("span",{children:Ee(U.timestamp)})]}),e.jsx("div",{className:X("rounded-2xl px-3 py-2 text-sm whitespace-pre-wrap break-words",U.type==="bot"?"bg-muted rounded-tl-sm":"bg-primary text-primary-foreground rounded-tr-sm"),children:U.content})]})]})]},U.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:j,onChange:U=>p(U.target.value),onKeyDown:De,placeholder:x?.isConnected?"输入消息...":"等待连接...",disabled:!x?.isConnected,className:"flex-1 h-10 sm:h-10"}),e.jsx(N,{onClick:ce,disabled:!x?.isConnected||!j.trim(),size:"icon",className:"h-10 w-10 shrink-0",children:e.jsx(Bb,{className:"h-4 w-4"})})]})})})]})}function X2(){const n=ja(),[i,c]=u.useState(!0);return u.useEffect(()=>{let d=!1;return(async()=>{try{const f=await Iu();!d&&!f&&n({to:"/auth"})}catch{d||n({to:"/auth"})}finally{d||c(!1)}})(),()=>{d=!0}},[n]),{checking:i}}async function K2(){return await Iu()}const J2=ci("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"}}),Fg=u.forwardRef(({className:n,size:i,abbrTitle:c,children:d,...h},f)=>e.jsx("kbd",{className:X(J2({size:i,className:n})),ref:f,...h,children:c?e.jsx("abbr",{title:c,children:d}):d}));Fg.displayName="Kbd";const Z2=[{icon:ao,title:"首页",description:"查看仪表板概览",path:"/",category:"概览"},{icon:Ra,title:"麦麦主程序配置",description:"配置麦麦的核心设置",path:"/config/bot",category:"配置"},{icon:fg,title:"麦麦模型提供商配置",description:"配置模型提供商",path:"/config/modelProvider",category:"配置"},{icon:pg,title:"麦麦模型配置",description:"配置模型参数",path:"/config/model",category:"配置"},{icon:$u,title:"表情包管理",description:"管理麦麦的表情包",path:"/resource/emoji",category:"资源"},{icon:un,title:"表达方式管理",description:"管理麦麦的表达方式",path:"/resource/expression",category:"资源"},{icon:gg,title:"人物信息管理",description:"管理人物信息",path:"/resource/person",category:"资源"},{icon:ri,title:"黑话管理",description:"管理麦麦学习到的黑话和俚语",path:"/resource/jargon",category:"资源"},{icon:Hb,title:"统计信息",description:"查看使用统计",path:"/statistics",category:"监控"},{icon:dn,title:"插件市场",description:"浏览和安装插件",path:"/plugins",category:"扩展"},{icon:Qu,title:"日志查看器",description:"查看系统日志",path:"/logs",category:"监控"},{icon:oi,title:"系统设置",description:"配置系统参数",path:"/settings",category:"系统"}];function I2({open:n,onOpenChange:i}){const[c,d]=u.useState(""),[h,f]=u.useState(0),x=ja(),j=Z2.filter(v=>v.title.toLowerCase().includes(c.toLowerCase())||v.description.toLowerCase().includes(c.toLowerCase())||v.category.toLowerCase().includes(c.toLowerCase()));u.useEffect(()=>{n&&(d(""),f(0))},[n]);const p=u.useCallback(v=>{x({to:v}),i(!1)},[x,i]),w=u.useCallback(v=>{v.key==="ArrowDown"?(v.preventDefault(),f(y=>(y+1)%j.length)):v.key==="ArrowUp"?(v.preventDefault(),f(y=>(y-1+j.length)%j.length)):v.key==="Enter"&&j[h]&&(v.preventDefault(),p(j[h].path))},[j,h,p]);return e.jsx($s,{open:n,onOpenChange:i,children:e.jsxs(Hs,{className:"max-w-2xl p-0 gap-0",children:[e.jsxs(qs,{className:"px-4 pt-4 pb-0",children:[e.jsx(Gs,{className:"sr-only",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx(zt,{className:"absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground"}),e.jsx(ie,{value:c,onChange:v=>{d(v.target.value),f(0)},onKeyDown:w,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(ss,{className:"h-[400px]",children:j.length>0?e.jsx("div",{className:"p-2",children:j.map((v,y)=>{const S=v.icon;return e.jsxs("button",{onClick:()=>p(v.path),onMouseEnter:()=>f(y),className:X("w-full flex items-center gap-3 px-3 py-2.5 rounded-md text-left transition-colors",y===h?"bg-accent text-accent-foreground":"hover:bg-accent/50"),children:[e.jsx(S,{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(zt,{className:"h-12 w-12 text-muted-foreground/50 mb-4"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:c?"未找到匹配的页面":"输入关键词开始搜索"})]})})}),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 P2=cb,W2=ob,e_=db,$g=u.forwardRef(({className:n,sideOffset:i=4,...c},d)=>e.jsx(rb,{children:e.jsx(sg,{ref:d,sideOffset:i,className:X("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),...c})}));$g.displayName=sg.displayName;function s_({children:n}){const{checking:i}=X2(),[c,d]=u.useState(!0),[h,f]=u.useState(!1),[x,j]=u.useState(!1),{theme:p,setTheme:w}=Xu(),v=dN();if(u.useEffect(()=>{const Y=L=>{(L.metaKey||L.ctrlKey)&&L.key==="k"&&(L.preventDefault(),j(!0))};return window.addEventListener("keydown",Y),()=>window.removeEventListener("keydown",Y)},[]),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:ao,label:"首页",path:"/"}]},{title:"麦麦配置编辑",items:[{icon:Ra,label:"麦麦主程序配置",path:"/config/bot"},{icon:fg,label:"AI模型厂商配置",path:"/config/modelProvider",tourId:"sidebar-model-provider"},{icon:pg,label:"模型管理与分配",path:"/config/model",tourId:"sidebar-model-management"},{icon:Zf,label:"麦麦适配器配置",path:"/config/adapter"}]},{title:"麦麦资源管理",items:[{icon:$u,label:"表情包管理",path:"/resource/emoji"},{icon:un,label:"表达方式管理",path:"/resource/expression"},{icon:ri,label:"黑话管理",path:"/resource/jargon"},{icon:gg,label:"人物信息管理",path:"/resource/person"},{icon:xg,label:"知识库图谱可视化",path:"/resource/knowledge-graph"}]},{title:"扩展与监控",items:[{icon:dn,label:"插件市场",path:"/plugins"},{icon:Zf,label:"插件配置",path:"/plugin-config"},{icon:Qu,label:"日志查看器",path:"/logs"},{icon:un,label:"本地聊天室",path:"/chat"}]},{title:"系统",items:[{icon:oi,label:"系统设置",path:"/settings"}]}],k=p==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":p,O=async()=>{await c0()};return e.jsx(P2,{delayDuration:300,children:e.jsxs("div",{className:"flex h-screen overflow-hidden",children:[e.jsxs("aside",{className:X("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",c?"lg:w-64":"lg:w-16",h?"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:X("relative flex items-center justify-center flex-1 transition-all overflow-hidden","lg:flex-1",!c&&"lg:flex-none lg:w-8"),children:[e.jsxs("div",{className:X("flex items-baseline gap-2",!c&&"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:Yy()})]}),!c&&e.jsx("span",{className:"hidden lg:block font-bold text-primary-gradient text-2xl",children:"M"})]})}),e.jsx(ss,{className:X("flex-1 overflow-x-hidden",!c&&"lg:w-16"),children:e.jsx("nav",{className:X("p-4",!c&&"lg:p-2 lg:w-16"),children:e.jsx("ul",{className:X("space-y-6",!c&&"lg:space-y-3 lg:w-full"),children:y.map((Y,L)=>e.jsxs("li",{children:[e.jsx("div",{className:X("px-3 h-[1.25rem]","mb-2",!c&&"lg:mb-1 lg:invisible"),children:e.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-muted-foreground/60 whitespace-nowrap",children:Y.title})}),!c&&L>0&&e.jsx("div",{className:"hidden lg:block mb-2 border-t border-border"}),e.jsx("ul",{className:"space-y-1",children:Y.items.map(R=>{const H=v({to:R.path}),D=R.icon,C=e.jsxs(e.Fragment,{children:[H&&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:X("flex items-center transition-all duration-300",c?"gap-3":"gap-3 lg:gap-0"),children:[e.jsx(D,{className:X("h-5 w-5 flex-shrink-0",H&&"text-primary"),strokeWidth:2,fill:"none"}),e.jsx("span",{className:X("text-sm font-medium whitespace-nowrap transition-all duration-300",H&&"font-semibold",c?"opacity-100 max-w-[200px]":"opacity-100 max-w-[200px] lg:opacity-0 lg:max-w-0 lg:overflow-hidden"),children:R.label})]})]});return e.jsx("li",{className:"relative",children:e.jsxs(W2,{children:[e.jsx(e_,{asChild:!0,children:e.jsx(Yc,{to:R.path,"data-tour":R.tourId,className:X("relative flex items-center rounded-lg py-2 transition-all duration-300","hover:bg-accent hover:text-accent-foreground",H?"bg-accent text-foreground":"text-muted-foreground hover:text-foreground",c?"px-3":"px-3 lg:px-0 lg:justify-center lg:w-12 lg:mx-auto"),onClick:()=>f(!1),children:C})}),!c&&e.jsx($g,{side:"right",className:"hidden lg:block",children:e.jsx("p",{children:R.label})})]})},R.path)})})]},Y.title))})})})]}),h&&e.jsx("div",{className:"fixed inset-0 z-40 bg-black/50 lg:hidden",onClick:()=>f(!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:()=>f(!h),className:"rounded-lg p-2 hover:bg-accent lg:hidden",children:e.jsx(qb,{className:"h-5 w-5"})}),e.jsx("button",{onClick:()=>d(!c),className:"hidden rounded-lg p-2 hover:bg-accent lg:block",title:c?"收起侧边栏":"展开侧边栏",children:e.jsx(Hl,{className:X("h-5 w-5 transition-transform",!c&&"rotate-180")})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>j(!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(zt,{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(Fg,{size:"sm",className:"absolute right-2 top-1/2 -translate-y-1/2",children:[e.jsx("span",{className:"text-xs",children:"⌘"}),"K"]})]}),e.jsx(I2,{open:x,onOpenChange:j}),e.jsxs(N,{variant:"ghost",size:"sm",onClick:()=>window.open("https://docs.mai-mai.org","_blank"),className:"gap-2",title:"查看麦麦文档",children:[e.jsx(Gb,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"麦麦文档"})]}),e.jsx("button",{onClick:Y=>{Gy(k==="dark"?"light":"dark",w,Y)},className:"rounded-lg p-2 hover:bg-accent",title:k==="dark"?"切换到浅色模式":"切换到深色模式",children:k==="dark"?e.jsx(og,{className:"h-5 w-5"}):e.jsx(dg,{className:"h-5 w-5"})}),e.jsx("div",{className:"h-6 w-px bg-border"}),e.jsxs(N,{variant:"ghost",size:"sm",onClick:O,className:"gap-2",title:"登出系统",children:[e.jsx(Vb,{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 t_(n){const i=n.split(` +`).slice(1),c=[];for(const d of i){const h=d.trim();if(!h.startsWith("at "))continue;const f=h.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/);f?c.push({functionName:f[1]||"",fileName:f[2],lineNumber:f[3],columnNumber:f[4],raw:h}):c.push({functionName:"",fileName:"",lineNumber:"",columnNumber:"",raw:h})}return c}function a_({error:n,errorInfo:i}){const[c,d]=u.useState(!0),[h,f]=u.useState(!1),[x,j]=u.useState(!1),p=n.stack?t_(n.stack):[],w=async()=>{const v=` Error: ${n.name} Message: ${n.message} @@ -49,4 +51,4 @@ ${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),j(!0),setTimeout(()=>j(!1),2e3)}catch(y){console.error("Failed to copy:",y)}};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(cl,{variant:"destructive",className:"border-red-500/50 bg-red-500/10",children:[e.jsx(ya,{className:"h-4 w-4"}),e.jsxs(ol,{className:"font-mono text-sm",children:[e.jsxs("span",{className:"font-semibold",children:[n.name,":"]})," ",n.message]})]}),p.length>0&&e.jsxs(Bu,{open:c,onOpenChange:d,children:[e.jsx(Hu,{asChild:!0,children:e.jsxs(N,{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(Hb,{className:"h-4 w-4"}),"Stack Trace (",p.length," frames)"]}),c?e.jsx(pr,{className:"h-4 w-4"}):e.jsx(Bl,{className:"h-4 w-4"})]})}),e.jsx(qu,{children:e.jsx(ss,{className:"h-[280px] rounded-md border bg-muted/30",children:e.jsx("div",{className:"p-3 space-y-1",children:p.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(Bu,{open:h,onOpenChange:x,children:[e.jsx(Hu,{asChild:!0,children:e.jsxs(N,{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(ya,{className:"h-4 w-4"}),"Component Stack"]}),h?e.jsx(pr,{className:"h-4 w-4"}):e.jsx(Bl,{className:"h-4 w-4"})]})}),e.jsx(qu,{children:e.jsx(ss,{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(N,{variant:"outline",size:"sm",onClick:w,className:"w-full",children:f?e.jsxs(e.Fragment,{children:[e.jsx(sa,{className:"mr-2 h-4 w-4 text-green-500"}),"已复制到剪贴板"]}):e.jsxs(e.Fragment,{children:[e.jsx(Pc,{className:"mr-2 h-4 w-4"}),"复制错误信息"]})})]})}function Gg({error:n,errorInfo:i}){const c=()=>{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(Ze,{className:"w-full max-w-2xl shadow-lg",children:[e.jsxs(ys,{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(ya,{className:"h-8 w-8 text-red-600 dark:text-red-400"})}),e.jsx(ws,{className:"text-2xl font-bold",children:"页面出现了问题"}),e.jsx(ct,{className:"text-base mt-2",children:"应用程序遇到了意外错误。您可以尝试刷新页面或返回首页。"})]}),e.jsxs(Ts,{className:"space-y-4",children:[e.jsx(J2,{error:n,errorInfo:i}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-2",children:[e.jsxs(N,{onClick:d,className:"flex-1",children:[e.jsx(Ct,{className:"mr-2 h-4 w-4"}),"刷新页面"]}),e.jsxs(N,{onClick:c,variant:"outline",className:"flex-1",children:[e.jsx(ao,{className:"mr-2 h-4 w-4"}),"返回首页"]})]}),e.jsx("p",{className:"text-xs text-center text-muted-foreground pt-2",children:"如果问题持续存在,请将错误信息复制并反馈给开发者"})]})]})})}class Z2 extends u.Component{constructor(i){super(i),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(i){return{hasError:!0,error:i}}componentDidCatch(i,c){console.error("ErrorBoundary caught an error:",i,c),this.setState({errorInfo:c})}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(Gg,{error:this.state.error,errorInfo:this.state.errorInfo}):this.props.children}}function Vg({error:n}){return e.jsx(Gg,{error:n,errorInfo:null})}const Sr=rN({component:()=>e.jsxs(e.Fragment,{children:[e.jsx(vp,{}),!1]}),beforeLoad:()=>{if(window.location.pathname==="/"&&!q2())throw oN({to:"/auth"})}}),I2=ft({getParentRoute:()=>Sr,path:"/auth",component:n0}),P2=ft({getParentRoute:()=>Sr,path:"/setup",component:y0}),Tt=ft({getParentRoute:()=>Sr,id:"protected",component:()=>e.jsx(X2,{children:e.jsx(vp,{})}),errorComponent:({error:n})=>e.jsx(Vg,{error:n})}),W2=ft({getParentRoute:()=>Tt,path:"/",component:Ry}),e_=ft({getParentRoute:()=>Tt,path:"/config/bot",component:R0}),s_=ft({getParentRoute:()=>Tt,path:"/config/modelProvider",component:nw}),t_=ft({getParentRoute:()=>Tt,path:"/config/model",component:ow}),a_=ft({getParentRoute:()=>Tt,path:"/config/adapter",component:uw}),l_=ft({getParentRoute:()=>Tt,path:"/resource/emoji",component:Rw}),n_=ft({getParentRoute:()=>Tt,path:"/resource/expression",component:Xw}),i_=ft({getParentRoute:()=>Tt,path:"/resource/person",component:g1}),r_=ft({getParentRoute:()=>Tt,path:"/resource/jargon",component:r1}),c_=ft({getParentRoute:()=>Tt,path:"/resource/knowledge-graph",component:C1}),o_=ft({getParentRoute:()=>Tt,path:"/logs",component:a2}),d_=ft({getParentRoute:()=>Tt,path:"/chat",component:B2}),u_=ft({getParentRoute:()=>Tt,path:"/plugins",component:k2}),m_=ft({getParentRoute:()=>Tt,path:"/plugin-config",component:z2}),h_=ft({getParentRoute:()=>Tt,path:"/plugin-mirrors",component:A2}),x_=ft({getParentRoute:()=>Tt,path:"/settings",component:Py}),f_=ft({getParentRoute:()=>Sr,path:"*",component:kg}),p_=Sr.addChildren([I2,P2,Tt.addChildren([W2,e_,s_,t_,a_,l_,n_,r_,i_,c_,u_,m_,h_,o_,d_,x_]),f_]),g_=cN({routeTree:p_,defaultNotFoundComponent:kg,defaultErrorComponent:({error:n})=>e.jsx(Vg,{error:n})});function j_({children:n,defaultTheme:i="system",storageKey:c="ui-theme",...d}){const[h,x]=u.useState(()=>localStorage.getItem(c)||i);u.useEffect(()=>{const j=window.document.documentElement;if(j.classList.remove("light","dark"),h==="system"){const p=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";j.classList.add(p);return}j.classList.add(h)},[h]),u.useEffect(()=>{const j=localStorage.getItem("accent-color");if(j){const p=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%)"}}[j];v&&(p.style.setProperty("--primary",v.hsl),v.gradient?(p.style.setProperty("--primary-gradient",v.gradient),p.classList.add("has-gradient")):(p.style.removeProperty("--primary-gradient"),p.classList.remove("has-gradient")))}},[]);const f={theme:h,setTheme:j=>{localStorage.setItem(c,j),x(j)}};return e.jsx(bg.Provider,{...d,value:f,children:n})}function v_({children:n,defaultEnabled:i=!0,defaultWavesEnabled:c=!0,storageKey:d="enable-animations",wavesStorageKey:h="enable-waves-background"}){const[x,f]=u.useState(()=>{const v=localStorage.getItem(d);return v!==null?v==="true":i}),[j,p]=u.useState(()=>{const v=localStorage.getItem(h);return v!==null?v==="true":c});u.useEffect(()=>{const v=document.documentElement;x?v.classList.remove("no-animations"):v.classList.add("no-animations"),localStorage.setItem(d,String(x))},[x,d]),u.useEffect(()=>{localStorage.setItem(h,String(j))},[j,h]);const w={enableAnimations:x,setEnableAnimations:f,enableWavesBackground:j,setEnableWavesBackground:p};return e.jsx(yg.Provider,{value:w,children:n})}const N_=rb,Fg=u.forwardRef(({className:n,...i},c)=>e.jsx(Wp,{ref:c,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),...i}));Fg.displayName=Wp.displayName;const b_=ci("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"}}),$g=u.forwardRef(({className:n,variant:i,...c},d)=>e.jsx(eg,{ref:d,className:$(b_({variant:i}),n),...c}));$g.displayName=eg.displayName;const y_=u.forwardRef(({className:n,...i},c)=>e.jsx(sg,{ref:c,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),...i}));y_.displayName=sg.displayName;const Qg=u.forwardRef(({className:n,...i},c)=>e.jsx(tg,{ref:c,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":"",...i,children:e.jsx(dl,{className:"h-4 w-4"})}));Qg.displayName=tg.displayName;const Yg=u.forwardRef(({className:n,...i},c)=>e.jsx(ag,{ref:c,className:$("text-sm font-semibold [&+div]:text-xs",n),...i}));Yg.displayName=ag.displayName;const Xg=u.forwardRef(({className:n,...i},c)=>e.jsx(lg,{ref:c,className:$("text-sm opacity-90",n),...i}));Xg.displayName=lg.displayName;function w_(){const{toasts:n}=Gs();return e.jsxs(N_,{children:[n.map(function({id:i,title:c,description:d,action:h,...x}){return e.jsxs($g,{...x,children:[e.jsxs("div",{className:"grid gap-1",children:[c&&e.jsx(Yg,{children:c}),d&&e.jsx(Xg,{children:d})]}),h,e.jsx(Qg,{})]},i)}),e.jsx(Fg,{})]})}_y.createRoot(document.getElementById("root")).render(e.jsx(u.StrictMode,{children:e.jsx(Z2,{children:e.jsx(j_,{defaultTheme:"system",children:e.jsx(v_,{children:e.jsxs(ew,{children:[e.jsx(dN,{router:g_}),e.jsx(aw,{}),e.jsx(w_,{})]})})})})})); + `.trim();try{await navigator.clipboard.writeText(v),j(!0),setTimeout(()=>j(!1),2e3)}catch(y){console.error("Failed to copy:",y)}};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(cl,{variant:"destructive",className:"border-red-500/50 bg-red-500/10",children:[e.jsx(_a,{className:"h-4 w-4"}),e.jsxs(ol,{className:"font-mono text-sm",children:[e.jsxs("span",{className:"font-semibold",children:[n.name,":"]})," ",n.message]})]}),p.length>0&&e.jsxs(Gu,{open:c,onOpenChange:d,children:[e.jsx(Vu,{asChild:!0,children:e.jsxs(N,{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(Fb,{className:"h-4 w-4"}),"Stack Trace (",p.length," frames)"]}),c?e.jsx(pr,{className:"h-4 w-4"}):e.jsx(Bl,{className:"h-4 w-4"})]})}),e.jsx(Fu,{children:e.jsx(ss,{className:"h-[280px] rounded-md border bg-muted/30",children:e.jsx("div",{className:"p-3 space-y-1",children:p.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(Gu,{open:h,onOpenChange:f,children:[e.jsx(Vu,{asChild:!0,children:e.jsxs(N,{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(_a,{className:"h-4 w-4"}),"Component Stack"]}),h?e.jsx(pr,{className:"h-4 w-4"}):e.jsx(Bl,{className:"h-4 w-4"})]})}),e.jsx(Fu,{children:e.jsx(ss,{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(N,{variant:"outline",size:"sm",onClick:w,className:"w-full",children:x?e.jsxs(e.Fragment,{children:[e.jsx($t,{className:"mr-2 h-4 w-4 text-green-500"}),"已复制到剪贴板"]}):e.jsxs(e.Fragment,{children:[e.jsx(Pc,{className:"mr-2 h-4 w-4"}),"复制错误信息"]})})]})}function Qg({error:n,errorInfo:i}){const c=()=>{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(Ze,{className:"w-full max-w-2xl shadow-lg",children:[e.jsxs(ys,{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(_a,{className:"h-8 w-8 text-red-600 dark:text-red-400"})}),e.jsx(ws,{className:"text-2xl font-bold",children:"页面出现了问题"}),e.jsx(ct,{className:"text-base mt-2",children:"应用程序遇到了意外错误。您可以尝试刷新页面或返回首页。"})]}),e.jsxs(Ts,{className:"space-y-4",children:[e.jsx(a_,{error:n,errorInfo:i}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-2",children:[e.jsxs(N,{onClick:d,className:"flex-1",children:[e.jsx(Ct,{className:"mr-2 h-4 w-4"}),"刷新页面"]}),e.jsxs(N,{onClick:c,variant:"outline",className:"flex-1",children:[e.jsx(ao,{className:"mr-2 h-4 w-4"}),"返回首页"]})]}),e.jsx("p",{className:"text-xs text-center text-muted-foreground pt-2",children:"如果问题持续存在,请将错误信息复制并反馈给开发者"})]})]})})}class l_ extends u.Component{constructor(i){super(i),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(i){return{hasError:!0,error:i}}componentDidCatch(i,c){console.error("ErrorBoundary caught an error:",i,c),this.setState({errorInfo:c})}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(Qg,{error:this.state.error,errorInfo:this.state.errorInfo}):this.props.children}}function Yg({error:n}){return e.jsx(Qg,{error:n,errorInfo:null})}const Sr=uN({component:()=>e.jsxs(e.Fragment,{children:[e.jsx(yp,{}),!1]}),beforeLoad:()=>{if(window.location.pathname==="/"&&!K2())throw hN({to:"/auth"})}}),n_=ft({getParentRoute:()=>Sr,path:"/auth",component:o0}),i_=ft({getParentRoute:()=>Sr,path:"/setup",component:C0}),Tt=ft({getParentRoute:()=>Sr,id:"protected",component:()=>e.jsx(s_,{children:e.jsx(yp,{})}),errorComponent:({error:n})=>e.jsx(Yg,{error:n})}),r_=ft({getParentRoute:()=>Tt,path:"/",component:Hy}),c_=ft({getParentRoute:()=>Tt,path:"/config/bot",component:H0}),o_=ft({getParentRoute:()=>Tt,path:"/config/modelProvider",component:ow}),d_=ft({getParentRoute:()=>Tt,path:"/config/model",component:gw}),u_=ft({getParentRoute:()=>Tt,path:"/config/adapter",component:vw}),m_=ft({getParentRoute:()=>Tt,path:"/resource/emoji",component:Fw}),h_=ft({getParentRoute:()=>Tt,path:"/resource/expression",component:s1}),x_=ft({getParentRoute:()=>Tt,path:"/resource/person",component:S1}),f_=ft({getParentRoute:()=>Tt,path:"/resource/jargon",component:f1}),p_=ft({getParentRoute:()=>Tt,path:"/resource/knowledge-graph",component:O1}),g_=ft({getParentRoute:()=>Tt,path:"/logs",component:u2}),j_=ft({getParentRoute:()=>Tt,path:"/chat",component:Y2}),v_=ft({getParentRoute:()=>Tt,path:"/plugins",component:R2}),N_=ft({getParentRoute:()=>Tt,path:"/plugin-config",component:B2}),b_=ft({getParentRoute:()=>Tt,path:"/plugin-mirrors",component:H2}),y_=ft({getParentRoute:()=>Tt,path:"/settings",component:t0}),w_=ft({getParentRoute:()=>Sr,path:"*",component:zg}),__=Sr.addChildren([n_,i_,Tt.addChildren([r_,c_,o_,d_,u_,m_,h_,f_,x_,p_,v_,N_,b_,g_,j_,y_]),w_]),S_=mN({routeTree:__,defaultNotFoundComponent:zg,defaultErrorComponent:({error:n})=>e.jsx(Yg,{error:n})});function C_({children:n,defaultTheme:i="system",storageKey:c="ui-theme",...d}){const[h,f]=u.useState(()=>localStorage.getItem(c)||i);u.useEffect(()=>{const j=window.document.documentElement;if(j.classList.remove("light","dark"),h==="system"){const p=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";j.classList.add(p);return}j.classList.add(h)},[h]),u.useEffect(()=>{const j=localStorage.getItem("accent-color");if(j){const p=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%)"}}[j];v&&(p.style.setProperty("--primary",v.hsl),v.gradient?(p.style.setProperty("--primary-gradient",v.gradient),p.classList.add("has-gradient")):(p.style.removeProperty("--primary-gradient"),p.classList.remove("has-gradient")))}},[]);const x={theme:h,setTheme:j=>{localStorage.setItem(c,j),f(j)}};return e.jsx(_g.Provider,{...d,value:x,children:n})}function k_({children:n,defaultEnabled:i=!0,defaultWavesEnabled:c=!0,storageKey:d="enable-animations",wavesStorageKey:h="enable-waves-background"}){const[f,x]=u.useState(()=>{const v=localStorage.getItem(d);return v!==null?v==="true":i}),[j,p]=u.useState(()=>{const v=localStorage.getItem(h);return v!==null?v==="true":c});u.useEffect(()=>{const v=document.documentElement;f?v.classList.remove("no-animations"):v.classList.add("no-animations"),localStorage.setItem(d,String(f))},[f,d]),u.useEffect(()=>{localStorage.setItem(h,String(j))},[j,h]);const w={enableAnimations:f,setEnableAnimations:x,enableWavesBackground:j,setEnableWavesBackground:p};return e.jsx(Sg.Provider,{value:w,children:n})}const T_=ub,Xg=u.forwardRef(({className:n,...i},c)=>e.jsx(tg,{ref:c,className:X("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),...i}));Xg.displayName=tg.displayName;const E_=ci("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"}}),Kg=u.forwardRef(({className:n,variant:i,...c},d)=>e.jsx(ag,{ref:d,className:X(E_({variant:i}),n),...c}));Kg.displayName=ag.displayName;const z_=u.forwardRef(({className:n,...i},c)=>e.jsx(lg,{ref:c,className:X("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),...i}));z_.displayName=lg.displayName;const Jg=u.forwardRef(({className:n,...i},c)=>e.jsx(ng,{ref:c,className:X("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":"",...i,children:e.jsx(dl,{className:"h-4 w-4"})}));Jg.displayName=ng.displayName;const Zg=u.forwardRef(({className:n,...i},c)=>e.jsx(ig,{ref:c,className:X("text-sm font-semibold [&+div]:text-xs",n),...i}));Zg.displayName=ig.displayName;const Ig=u.forwardRef(({className:n,...i},c)=>e.jsx(rg,{ref:c,className:X("text-sm opacity-90",n),...i}));Ig.displayName=rg.displayName;function A_(){const{toasts:n}=Vs();return e.jsxs(T_,{children:[n.map(function({id:i,title:c,description:d,action:h,...f}){return e.jsxs(Kg,{...f,children:[e.jsxs("div",{className:"grid gap-1",children:[c&&e.jsx(Zg,{children:c}),d&&e.jsx(Ig,{children:d})]}),h,e.jsx(Jg,{})]},i)}),e.jsx(Xg,{})]})}Ty.createRoot(document.getElementById("root")).render(e.jsx(u.StrictMode,{children:e.jsx(l_,{children:e.jsx(C_,{defaultTheme:"system",children:e.jsx(k_,{children:e.jsxs(lw,{children:[e.jsx(xN,{router:S_}),e.jsx(rw,{}),e.jsx(A_,{})]})})})})})); diff --git a/webui/dist/index.html b/webui/dist/index.html index 66ce72c0..30c422b4 100644 --- a/webui/dist/index.html +++ b/webui/dist/index.html @@ -7,7 +7,7 @@ MaiBot Dashboard - + @@ -21,7 +21,7 @@ - +