diff --git a/backend/agent_factory.py b/backend/agent_factory.py index 1e52a10..3a6cb88 100644 --- a/backend/agent_factory.py +++ b/backend/agent_factory.py @@ -36,7 +36,7 @@ set_tracing_disabled(True) def create_agent(**kwargs) -> Agent: # 通过用户配置拿/环境变量 client = AsyncOpenAI( - api_key="aib_ComfyUI_Copilot_8d28a3", + api_key="", base_url="https://comfyui-copilot-server-pre.onrender.com/v1", ) diff --git a/backend/controller/conversation_api.py b/backend/controller/conversation_api.py index 11b6821..7c7eb62 100644 --- a/backend/controller/conversation_api.py +++ b/backend/controller/conversation_api.py @@ -19,7 +19,7 @@ import sys import os from ..service.debug_agent import debug_workflow_errors -from ..service.database import save_workflow_data, get_workflow_data_by_id +from ..service.database import save_workflow_data, get_workflow_data_by_id, update_workflow_ui_by_id from ..service.mcp_client import comfyui_agent_invoke, ImageData @@ -330,7 +330,7 @@ async def invoke_chat(request): intent = req_json.get('intent') ext = req_json.get('ext') historical_messages = req_json.get('messages', []) - workflow_data = req_json.get('workflow_data') + workflow_checkpoint_id = req_json.get('workflow_checkpoint_id') # 获取当前语言 language = request.headers.get('Accept-Language', 'en') @@ -345,24 +345,11 @@ async def invoke_chat(request): # 历史消息已经从前端传递过来,格式为OpenAI格式,直接使用 print(f"-- Received {len(historical_messages)} historical messages") - # Save current workflow data to database if provided - if workflow_data and session_id: - try: - print(f"Saving workflow data for session {session_id}") - save_workflow_data( - session_id=session_id, - workflow_data=workflow_data, - workflow_data_ui=None, # UI format not available from frontend - attributes={ - "source": "frontend_current_workflow", - "description": "Current workflow data from canvas", - "timestamp": time.time() - } - ) - print(f"Successfully saved workflow data for session {session_id}") - except Exception as e: - print(f"Failed to save workflow data for session {session_id}: {str(e)}") - # Continue without failing the request + # Log workflow checkpoint ID if provided (workflow is now pre-saved before invoke) + if workflow_checkpoint_id: + print(f"Using workflow checkpoint ID: {workflow_checkpoint_id} for session {session_id}") + else: + print(f"No workflow checkpoint ID provided for session {session_id}") # 历史消息已经从前端传递过来,包含了正确格式的OpenAI消息(包括图片) # 直接使用前端传递的历史消息,无需重新构建当前消息 @@ -381,6 +368,7 @@ async def invoke_chat(request): config = { "session_id": session_id, # 添加session_id到配置中 + "workflow_checkpoint_id": workflow_checkpoint_id, # 添加工作流检查点ID "openai_api_key": request.headers.get('Openai-Api-Key'), "openai_base_url": request.headers.get('Openai-Base-Url'), "model_select": next((x['data'][0] for x in ext if x['type'] == 'model_select' and x.get('data')), None) @@ -468,7 +456,8 @@ async def save_workflow_checkpoint(request): session_id = req_json.get('session_id') workflow_api = req_json.get('workflow_api') # API format workflow workflow_ui = req_json.get('workflow_ui') # UI format workflow - checkpoint_type = req_json.get('checkpoint_type', 'debug_start') # debug_start or debug_complete + checkpoint_type = req_json.get('checkpoint_type', 'debug_start') # debug_start, debug_complete, user_message_checkpoint + message_id = req_json.get('message_id') # User message ID for linking (optional) if not session_id or not workflow_api: return web.json_response({ @@ -479,10 +468,19 @@ async def save_workflow_checkpoint(request): # Save workflow with checkpoint type in attributes attributes = { "checkpoint_type": checkpoint_type, - "description": f"Workflow checkpoint: {checkpoint_type}", "timestamp": time.time() } + # Set description and additional attributes based on checkpoint type + if checkpoint_type == "user_message_checkpoint" and message_id: + attributes.update({ + "description": f"Workflow checkpoint before user message {message_id}", + "message_id": message_id, + "source": "user_message_pre_invoke" + }) + else: + attributes["description"] = f"Workflow checkpoint: {checkpoint_type}" + version_id = save_workflow_data( session_id=session_id, workflow_data=workflow_api, @@ -492,12 +490,21 @@ async def save_workflow_checkpoint(request): print(f"Workflow checkpoint saved with version ID: {version_id}") + # Return response format based on checkpoint type + response_data = { + "version_id": version_id, + "checkpoint_type": checkpoint_type + } + + if checkpoint_type == "user_message_checkpoint" and message_id: + response_data.update({ + "checkpoint_id": version_id, # Add checkpoint_id alias for user message checkpoints + "message_id": message_id + }) + return web.json_response({ "success": True, - "data": { - "version_id": version_id, - "checkpoint_type": checkpoint_type - }, + "data": response_data, "message": f"Workflow checkpoint saved successfully" }) @@ -509,6 +516,7 @@ async def save_workflow_checkpoint(request): }) + @server.PromptServer.instance.routes.get("/api/restore-workflow-checkpoint") async def restore_workflow_checkpoint(request): """ @@ -746,3 +754,52 @@ async def invoke_debug(request): await response.write_eof() return response + + +@server.PromptServer.instance.routes.post("/api/update-workflow-ui") +async def update_workflow_ui(request): + """ + Update workflow_data_ui field for a specific checkpoint without affecting other fields + """ + print("Received update-workflow-ui request") + req_json = await request.json() + + try: + checkpoint_id = req_json.get('checkpoint_id') + workflow_data_ui = req_json.get('workflow_data_ui') + + if not checkpoint_id or not workflow_data_ui: + return web.json_response({ + "success": False, + "message": "Missing required parameters: checkpoint_id and workflow_data_ui" + }) + + try: + checkpoint_id = int(checkpoint_id) + except ValueError: + return web.json_response({ + "success": False, + "message": "Invalid checkpoint_id format" + }) + + # Update only the workflow_data_ui field + success = update_workflow_ui_by_id(checkpoint_id, workflow_data_ui) + + if success: + print(f"Successfully updated workflow_data_ui for checkpoint ID: {checkpoint_id}") + return web.json_response({ + "success": True, + "message": f"Workflow UI data updated successfully for checkpoint {checkpoint_id}" + }) + else: + return web.json_response({ + "success": False, + "message": f"Checkpoint {checkpoint_id} not found" + }) + + except Exception as e: + print(f"Error updating workflow UI data: {str(e)}") + return web.json_response({ + "success": False, + "message": f"Failed to update workflow UI data: {str(e)}" + }) diff --git a/backend/data/workflow_rewrite_expert.json b/backend/data/workflow_rewrite_expert.json new file mode 100644 index 0000000..df62c7b --- /dev/null +++ b/backend/data/workflow_rewrite_expert.json @@ -0,0 +1,37 @@ +[ + { + "name": "添加LoRA", + "description": "在现有工作流中添加LoRA节点", + "content": "在现有工作流中添加LoRA节点,确保与现有模型和提示词节点正确连接\n 在checkpoint节点后添加LoRA节点。\n {\n \"1\": {\n \"inputs\": {\n \"lora_name\": \"DOG.safetensors\",\n \"strength_model\": 1,\n \"strength_clip\": 1,\n \"model\": [\n \"2\",\n 0\n ],\n \"clip\": [\n \"2\",\n 1\n ]\n },\n \"class_type\": \"LoraLoader\",\n \"_meta\": {\n \"title\": \"Load LoRA\"\n }\n }" + }, + { + "name": "后处理增强", + "description": "后处理增强,例如在Preview Image或Save Image节点后添加高清放大功能(如Real-ESRGAN、ESRGAN等); 或者添加图像缩放节点", + "content": "- 在Preview Image或Save Image节点后添加高清放大功能(如Real-ESRGAN、ESRGAN等)\n - 添加图像缩放节点\n {\n \"1\": {\n \"inputs\": {\n \"width\": 512,\n \"height\": 512,\n \"interpolation\": \"nearest\",\n \"method\": \"stretch\",\n \"condition\": \"always\",\n \"multiple_of\": 0\n },\n \"class_type\": \"ImageResize+\",\n \"_meta\": {\n \"title\": \"🔧 Image Resize\"\n }\n }\n}\n - 添加图像尺寸调整节点\n {\n \"2\": {\n \"inputs\": {\n \"aspect_ratio\": \"original\",\n \"proportional_width\": 2,\n \"proportional_height\": 1,\n \"fit\": \"letterbox\",\n \"method\": \"lanczos\",\n \"round_to_multiple\": \"8\",\n \"scale_to_longest_side\": false,\n \"longest_side\": 1024\n },\n \"class_type\": \"LayerUtility: ImageScaleByAspectRatio\",\n \"_meta\": {\n \"title\": \"LayerUtility: ImageScaleByAspectRatio\"\n }\n }\n}\n -添加图像放大节点\n \"11\": {\n \"inputs\": {\n \"width\": 512,\n \"height\": 512,\n \"upscale_method\": \"nearest-exact\",\n \"keep_proportion\": false,\n \"divisible_by\": 2,\n \"crop\": \"disabled\",\n \"image\": [\n \"12\",\n 0\n ]\n },\n \"class_type\": \"ImageResizeKJ\",\n \"_meta\": {\n \"title\": \"Resize Image\"\n }\n },\n -添加VAEdecode节点\n \"12\": {\n \"inputs\": {},\n \"class_type\": \"VAEDecode\",\n \"_meta\": {\n \"title\": \"VAE Decode\"\n }\n }\n}" + }, + { + "name": "提示词优化", + "description": "修改现有提示词节点的内容(提示词应该在(CLIP Text Encode Prompt或Text _O节点内编辑); 添加单独的提示词输入节点", + "content": "{\n \"12\": {\n \"inputs\": {\n \"text\": [\n \"13\",\n 0\n ]\n },\n \"class_type\": \"CLIPTextEncode\",\n \"_meta\": {\n \"title\": \"CLIP Text Encode (Prompt)\"\n }\n },\n \"13\": {\n \"inputs\": {\n \"delimiter\": \", \",\n \"clean_whitespace\": \"true\",\n \"text_a\": [\n \"15\",\n 0\n ],\n \"text_b\": [\n \"16\",\n 0\n ]\n },\n \"class_type\": \"Text Concatenate\",\n \"_meta\": {\n \"title\": \"Text Concatenate\"\n }\n },\n \"15\": {\n \"inputs\": {\n \"text\": \"\"\n },\n \"class_type\": \"Text _O\",\n \"_meta\": {\n \"title\": \"Text _O\"\n }\n },\n \"16\": {\n \"inputs\": {\n \"text\": \"\"\n },\n \"class_type\": \"Text _O\",\n \"_meta\": {\n \"title\": \"Text _O\"\n }\n }\n}" + }, + { + "name": "图像反推", + "description": "理解图片信息并用文字表达出来", + "content": "添加图像反推节点(如CLIP Interrogator)\n{\n \"11\": {\n \"inputs\": {\n \"prompt_mode\": \"fast\",\n \"image_analysis\": \"off\"\n },\n \"class_type\": \"ClipInterrogator\",\n \"_meta\": {\n \"title\": \"Clip Interrogator ♾️Mixlab\"\n }\n }\n}\n - 添加更复杂或者更好用的图像反推节点(加载图片使用florence2进行反推)\n {\n \"6\": {\n \"inputs\": {\n \"image\": \"06.JPG\"\n },\n \"class_type\": \"LoadImage\",\n \"_meta\": {\n \"title\": \"$image.image!:The image to analyze, must be a url\"\n }\n },\n \"10\": {\n \"inputs\": {\n \"model\": \"microsoft/Florence-2-large\",\n \"precision\": \"fp16\",\n \"attention\": \"sdpa\"\n },\n \"class_type\": \"DownloadAndLoadFlorence2Model\",\n \"_meta\": {\n \"title\": \"DownloadAndLoadFlorence2Model\"\n }\n },\n \"11\": {\n \"inputs\": {\n \"text_input\": \"\",\n \"task\": \"more_detailed_caption\",\n \"fill_mask\": true,\n \"keep_model_loaded\": false,\n \"max_new_tokens\": 1024,\n \"num_beams\": 3,\n \"do_sample\": true,\n \"output_mask_select\": \"\",\n \"seed\": 1098631327477633,\n \"image\": [\n \"6\",\n 0\n ],\n \"florence2_model\": [\n \"10\",\n 0\n ]\n },\n \"class_type\": \"Florence2Run\",\n \"_meta\": {\n \"title\": \"Florence2Run\"\n }\n },\n \"18\": {\n \"inputs\": {\n \"anything\": [\n \"11\",\n 2\n ]\n },\n \"class_type\": \"easy showAnything\",\n \"_meta\": {\n \"title\": \"Show Any\"\n }\n },\n \"20\": {\n \"inputs\": {\n \"value\": \"Generate high-quality text descriptions from images using local Florence model.\\n \\n Main use cases:\\n 1. **Reverse image prompt generation**:\\n - When users upload an image and want to get prompts for AI art generation\\n - Analyzes visual elements, style, composition, etc. to generate prompts for Stable Diffusion, DALL-E, and other models\\n - In this case, return the tool's raw output directly to users without any modification or summary\\n - Users can directly use these prompts for image generation\\n 2. **Image content understanding**:\\n - When users ask about specific content, objects, scenes, people, etc. in the image\\n - Need to understand the semantic content of the image and answer users' specific questions\\n - In this case, combine tool output with conversation context to give users contextually appropriate natural responses\\n - Don't return raw output directly, but provide targeted replies based on understanding results\"\n },\n \"class_type\": \"PrimitiveStringMultiline\",\n \"_meta\": {\n \"title\": \"MCP\"\n }\n }\n}" + }, + { + "name": "添加ControlNet", + "description": "在使用风格迁移保持主体结构不变、保持主体形状、重新绘制背景、控制人物角色姿态、保持场景的深度和空间结构、基于线稿或者草图生成图像等场景下,可以用添加ControlNet节点来实现", + "content": "**ControlNet集成**:(preprocessor可选canny、depth等参数,模型样式选择,Controlnet开始、结束权重)\n {\n \"22\": {\n \"inputs\": {\n \"strength\": 1,\n \"start_percent\": 0,\n \"end_percent\": 1,\n \"control_net\": [\n \"23\",\n 0\n ],\n \"image\": [\n \"24\",\n 0\n ]\n },\n \"class_type\": \"ControlNetApplyAdvanced\",\n \"_meta\": {\n \"title\": \"Apply ControlNet\"\n }\n },\n \"23\": {\n \"inputs\": {\n \"control_net_name\": \"ControlNet-Standard-Lineart-for-SDXL.safetensors\"\n },\n \"class_type\": \"ControlNetLoader\",\n \"_meta\": {\n \"title\": \"Load ControlNet Model\"\n }\n },\n \"24\": {\n \"inputs\": {\n \"preprocessor\": \"none\",\n \"resolution\": 512\n },\n \"class_type\": \"AIO_Preprocessor\",\n \"_meta\": {\n \"title\": \"AIO Aux Preprocessor\"\n }\n }\n}" + }, + { + "name": "扩图", + "description": "给我一个扩图链路(包括图像加载和图像输出)", + "content": "{\n \"1\": {\n \"inputs\": {\n \"image\": \"01.JPG\"\n },\n \"class_type\": \"LoadImage\",\n \"_meta\": {\n \"title\": \"$image.image!:The image to analyze, must be a url\"\n }\n },\n \"2\": {\n \"inputs\": {\n \"model\": \"runwayml/stable-diffusion-xl-base-1.0\",\n \"precision\": \"fp16\",\n \"attention\": \"sdpa\"\n },\n \"class_type\": \"DownloadAndLoadModel\",\n \"_meta\": {\n \"title\": \"DownloadAndLoadModel\"\n }\n },\n \"3\": {\n \"inputs\": {\n \"prompt\": \"A beautiful girl with long hair and a white dress\",\n \"image\": [\n \"1\",\n 0\n ],\n \"model\": [\n \"2\",\n 0\n ]\n },\n \"class_type\": \"StableDiffusionXLRun\",\n \"_meta\": {\n \"title\": \"StableDiffusionXLRun\"\n }\n },\n \"4\": {\n \"inputs\": {\n \"image\": [\n \"3\",\n 0\n ]\n },\n \"class_type\": \"easy showImage\",\n \"_meta\": {\n \"title\": \"Show Image\"\n }\n }\n}" + }, + { + "name": "智能抠图", + "description": "添加背景移除节点(如SAM、U²-Net等)", + "content": "- 添加背景移除或抠图节点\n {\n \"7\": {\n \"inputs\": {\n \"rem_mode\": \"RMBG-1.4\",\n \"image_output\": \"Preview\",\n \"save_prefix\": \"ComfyUI\",\n \"torchscript_jit\": false,\n \"add_background\": \"none\",\n \"refine_foreground\": false\n },\n \"class_type\": \"easy imageRemBg\",\n \"_meta\": {\n \"title\": \"Image Remove Bg\"\n }\n }\n}\n - 添加SAM抠图节点\n {\n \"8\": {\n \"inputs\": {\n \"prompt\": \"\",\n \"threshold\": 0.3,\n \"sam_model\": [\n \"9\",\n 0\n ],\n \"grounding_dino_model\": [\n \"10\",\n 0\n ]\n },\n \"class_type\": \"GroundingDinoSAMSegment (segment anything)\",\n \"_meta\": {\n \"title\": \"GroundingDinoSAMSegment (segment anything)\"\n }\n },\n \"9\": {\n \"inputs\": {\n \"model_name\": \"sam_vit_h (2.56GB)\"\n },\n \"class_type\": \"SAMModelLoader (segment anything)\",\n \"_meta\": {\n \"title\": \"SAMModelLoader (segment anything)\"\n }\n },\n \"10\": {\n \"inputs\": {\n \"model_name\": \"GroundingDINO_SwinT_OGC (694MB)\"\n },\n \"class_type\": \"GroundingDinoModelLoader (segment anything)\",\n \"_meta\": {\n \"title\": \"GroundingDinoModelLoader (segment anything)\"\n }\n }\n}" + } +] \ No newline at end of file diff --git a/backend/service/database.py b/backend/service/database.py index eb02e83..a1bd782 100644 --- a/backend/service/database.py +++ b/backend/service/database.py @@ -86,6 +86,21 @@ class DatabaseManager: finally: session.close() + def get_current_workflow_data_ui(self, session_id: str) -> Optional[Dict[str, Any]]: + """获取当前session的最新工作流数据(最大ID版本)""" + session = self.get_session() + try: + latest_version = session.query(WorkflowVersion)\ + .filter(WorkflowVersion.session_id == session_id)\ + .order_by(WorkflowVersion.id.desc())\ + .first() + + if latest_version: + return json.loads(latest_version.workflow_data_ui) + return None + finally: + session.close() + def get_workflow_version_by_id(self, version_id: int) -> Optional[Dict[str, Any]]: """根据版本ID获取工作流数据""" session = self.get_session() @@ -124,6 +139,25 @@ class DatabaseManager: raise e finally: session.close() + + def update_workflow_ui(self, version_id: int, workflow_data_ui: Dict[str, Any]) -> bool: + """只更新指定版本的workflow_data_ui字段,不影响其他字段""" + session = self.get_session() + try: + version = session.query(WorkflowVersion)\ + .filter(WorkflowVersion.id == version_id)\ + .first() + + if version: + version.workflow_data_ui = json.dumps(workflow_data_ui) + session.commit() + return True + return False + except Exception as e: + session.rollback() + raise e + finally: + session.close() # 全局数据库管理器实例 db_manager = DatabaseManager() @@ -132,10 +166,18 @@ def get_workflow_data(session_id: str) -> Optional[Dict[str, Any]]: """获取当前session的工作流数据的便捷函数""" return db_manager.get_current_workflow_data(session_id) +def get_workflow_data_ui(session_id: str) -> Optional[Dict[str, Any]]: + """获取当前session的工作流数据的便捷函数""" + return db_manager.get_current_workflow_data_ui(session_id) + def save_workflow_data(session_id: str, workflow_data: Dict[str, Any], workflow_data_ui: Dict[str, Any] = None, attributes: Optional[Dict[str, Any]] = None) -> int: """保存工作流数据的便捷函数""" return db_manager.save_workflow_version(session_id, workflow_data, workflow_data_ui, attributes) def get_workflow_data_by_id(version_id: int) -> Optional[Dict[str, Any]]: """根据版本ID获取工作流数据的便捷函数""" - return db_manager.get_workflow_version_by_id(version_id) \ No newline at end of file + return db_manager.get_workflow_version_by_id(version_id) + +def update_workflow_ui_by_id(version_id: int, workflow_data_ui: Dict[str, Any]) -> bool: + """只更新指定版本的workflow_data_ui字段的便捷函数""" + return db_manager.update_workflow_ui(version_id, workflow_data_ui) \ No newline at end of file diff --git a/backend/service/debug_agent.py b/backend/service/debug_agent.py index 5e221ed..b65a967 100644 --- a/backend/service/debug_agent.py +++ b/backend/service/debug_agent.py @@ -54,11 +54,8 @@ async def run_workflow(session_id: str) -> str: @function_tool def analyze_error_type(error_data: str) -> str: - """分析错误类型,判断应该使用哪个agent,输入应为JSON字符串""" + """分析错误类型,判断应该使用哪个agent,输入可以是JSON字符串或普通文本""" try: - # 解析JSON字符串 - error_dict = json.loads(error_data) if isinstance(error_data, str) else error_data - error_analysis = { "error_type": "unknown", "recommended_agent": "workflow_bugfix_default_agent", @@ -66,82 +63,95 @@ def analyze_error_type(error_data: str) -> str: "affected_nodes": [] } - # 检查新的返回格式 - if "success" in error_dict: - if error_dict["success"]: - # 工作流验证成功 - error_analysis["error_type"] = "no_error" - error_analysis["recommended_agent"] = "none" - error_analysis["error_details"] = [{"message": "Workflow validation successful"}] - return json.dumps(error_analysis) - else: - # 工作流验证失败,继续分析错误类型 - pass + # 将输入转换为字符串进行关键词匹配 + error_text = str(error_data).lower() - # 检查是否有node_errors (ComfyUI验证错误格式) - if "node_errors" in error_dict and error_dict["node_errors"]: - node_errors = error_dict["node_errors"] - parameter_errors = 0 - connection_errors = 0 - other_errors = 0 - - for node_id, node_error in node_errors.items(): - error_analysis["affected_nodes"].append(node_id) - - if "errors" in node_error: - for error in node_error["errors"]: - error_detail = { - "node_id": node_id, - "error_type": error.get("type", "unknown"), - "message": error.get("message", ""), - "details": error.get("details", "") - } - error_analysis["error_details"].append(error_detail) - - # 改进的错误类型判断 - error_detail_str = json.dumps(error_detail).lower() - error_type = error.get("type", "").lower() - # error_message = error.get("message", "").lower() - - # 优先判断连接相关错误(结构性错误) - if (any(keyword in error_detail_str for keyword in [ - "connection", "input connection", "required input", "missing input", - "not connected", "no connection", "link", "output", "socket" - ]) or - error_type in ["missing_input", "invalid_connection", "connection_error"]): - connection_errors += 1 - - # 参数相关错误的判断(更精确) - elif (error_type in ["value_not_in_list", "invalid_input", "invalid_value"] or - any(keyword in error_detail_str for keyword in [ - "value not in list", "invalid value", "not found in list", - "parameter value", "invalid parameter", "model not found", "invalid image file" - ])): - parameter_errors += 1 - - # 其他结构性错误 - else: - other_errors += 1 - - # 根据错误类型决定使用哪个agent - if connection_errors > 0 and parameter_errors == 0 and other_errors == 0: - # 纯连接错误,使用专门的link_agent - error_analysis["error_type"] = "connection_error" - error_analysis["recommended_agent"] = "link_agent" - elif connection_errors > 0: - # 混合错误,优先处理连接问题 - error_analysis["error_type"] = "mixed_connection_error" - error_analysis["recommended_agent"] = "link_agent" - elif parameter_errors > 0: - error_analysis["error_type"] = "parameter_error" - error_analysis["recommended_agent"] = "parameter_agent" - else: - error_analysis["error_type"] = "structural_error" - error_analysis["recommended_agent"] = "workflow_bugfix_default_agent" + # 检查成功状态 + if any(keyword in error_text for keyword in [ + '"success": true', "'success': true", "validation successful", "workflow validation successful" + ]): + error_analysis["error_type"] = "no_error" + error_analysis["recommended_agent"] = "none" + error_analysis["error_details"] = [{"message": "Workflow validation successful"}] + return json.dumps(error_analysis) + + # 统计不同类型的错误 + parameter_errors = 0 + connection_errors = 0 + other_errors = 0 + + # 提取节点ID(简单的正则匹配) + import re + node_id_matches = re.findall(r'"(\d+)":', error_text) or re.findall(r"'(\d+)':", error_text) + if node_id_matches: + error_analysis["affected_nodes"] = list(set(node_id_matches)) + + # 连接相关错误的关键词(优先判断,因为结构性错误更重要) + connection_keywords = [ + "connection", "input connection", "required input", "missing input", + "not connected", "no connection", "link", "output", "socket", + "missing_input", "invalid_connection", "connection_error" + ] + + # 参数相关错误的关键词 + parameter_keywords = [ + "value not in list", "invalid value", "not found in list", + "parameter value", "invalid parameter", "model not found", + "invalid image file", "value_not_in_list", "invalid_input" + ] + + # 计算错误类型出现次数 + for keyword in connection_keywords: + if keyword in error_text: + connection_errors += error_text.count(keyword) + + for keyword in parameter_keywords: + if keyword in error_text: + parameter_errors += error_text.count(keyword) + + # 如果没有匹配到特定错误类型,检查是否有一般性错误指示 + if connection_errors == 0 and parameter_errors == 0: + general_error_keywords = ["error", "failed", "exception", "invalid"] + for keyword in general_error_keywords: + if keyword in error_text: + other_errors += 1 + break + + # 根据错误类型决定使用哪个agent + if connection_errors > 0 and parameter_errors == 0 and other_errors == 0: + # 纯连接错误,使用专门的link_agent + error_analysis["error_type"] = "connection_error" + error_analysis["recommended_agent"] = "link_agent" + elif connection_errors > 0: + # 混合错误,优先处理连接问题 + error_analysis["error_type"] = "mixed_connection_error" + error_analysis["recommended_agent"] = "link_agent" + elif parameter_errors > 0: + error_analysis["error_type"] = "parameter_error" + error_analysis["recommended_agent"] = "parameter_agent" + elif other_errors > 0: + error_analysis["error_type"] = "structural_error" + error_analysis["recommended_agent"] = "workflow_bugfix_default_agent" + else: + # 没有检测到明确的错误模式,使用默认agent + error_analysis["error_type"] = "unknown" + error_analysis["recommended_agent"] = "workflow_bugfix_default_agent" + + # 添加错误详情(基于文本内容) + if connection_errors > 0: + error_analysis["error_details"].append({ + "error_type": "connection_error", + "message": f"Detected {connection_errors} connection-related issues", + "details": "Connection or input/output related errors found" + }) + + if parameter_errors > 0: + error_analysis["error_details"].append({ + "error_type": "parameter_error", + "message": f"Detected {parameter_errors} parameter-related issues", + "details": "Parameter value or configuration related errors found" + }) - elif "error" in error_dict: - # 处理其他格式的错误 - error_analysis = error_dict.get("error", {}) return json.dumps(error_analysis) except Exception as e: @@ -331,6 +341,7 @@ Start by validating the workflow to see its current state.""", - Review missing_connections and possible_connections from the analysis - Choose the most efficient combination of existing connections and new nodes - Consider connection_summary to understand the scope of work needed + - Do not lose or modify parameters that are not reporting errors 4. **Verification and handoff**: - After applying fixes: TRANSFER to ComfyUI-Debug-Coordinator for verification @@ -408,7 +419,7 @@ Start by validating the workflow to see its current state.""", * wan2.1 system (examples: wan2.1_base, wan2.1_t2v, etc.) * wan2.2 system (examples: wan2.2_t2v, wan2.2_iv2, wan2.2_kontext, wan2.2_redux, etc.) - Match by model system first (SDXL/Flux/wan2.1/wan2.2), then by model category (fill/dev/base/t2v/iv2/kontext/redux) - - **System-specific component matching rules:** + - [Critical!] **System-specific component matching rules:** * **Flux series**: Requires fixed system components - vae: ae.safetensors, DualCLIPLoader: clip_l.safetensors + t5xxl_fp16.safetensors or t5xxl_fp8.safetensors, type: flux. In DualCLIP and UNetLoader/Load Checkpoint, search by system+category (e.g., Flux-dev-fp8 can be replaced with similar Flux-dev) * **SDXL series**: vae: sdxl_vae.safetensors or vae-fe-mse-840000-ema-pruned.safetensors (priority search by system: vae, category: sdxl/840000). Load checkpoint search by system: sdxl, category: similar name (e.g., SDXL-dreamshaper.safetensors where dreamshaper is the category) - If similar model from same system exists, replace with most similar match diff --git a/backend/service/mcp_client.py b/backend/service/mcp_client.py index 12d33f4..0ef05af 100644 --- a/backend/service/mcp_client.py +++ b/backend/service/mcp_client.py @@ -2,7 +2,7 @@ Author: ai-business-hql qingli.hql@alibaba-inc.com Date: 2025-06-16 16:50:17 LastEditors: ai-business-hql qingli.hql@alibaba-inc.com -LastEditTime: 2025-07-31 20:16:19 +LastEditTime: 2025-08-06 14:54:19 FilePath: /comfyui_copilot/backend/service/mcp-client.py Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE ''' @@ -69,7 +69,7 @@ async def comfyui_agent_invoke(messages: List[Dict[str, Any]], images: List[Imag os.environ["OPENAI_BASE_URL"] = config.get("openai_base_url") # 创建带有session_id的workflow_rewrite_agent实例 - workflow_rewrite_agent_instance = create_workflow_rewrite_agent(session_id) + workflow_rewrite_agent_instance = create_workflow_rewrite_agent(session_id, config) agent = create_agent( name="ComfyUI-Copilot", @@ -100,7 +100,7 @@ You must adhere to the following constraints to complete the task: - **DEBUG Intent** - When the user's intent is to debug workflow execution problems, runtime errors, or troubleshoot failed workflows (keywords: "debug", "调试", "工作流报错", "执行失败", "workflow failed", "node error", "runtime error", "不能运行", "出错了"), respond with: "Please click the 🪲 button in the bottom right corner to trigger debug" -- **WORKFLOW REWRITE Intent** - [Critical!] When the user's intent is to functionally modify, enhance, or add NEW features to the current workflow (keywords: "修改当前工作流", "更新工作流", "在当前工作流中添加", "添加功能", "enhance current workflow", "modify workflow", "add to current workflow", "update current workflow", "添加LoRA", "加个upscale", "add upscaling"), you MUST handoff to the Workflow Rewrite Agent immediately. This is for feature enhancements, not error fixes. +- **WORKFLOW REWRITE Intent** - [Critical!] When the user's intent is to functionally modify, enhance, or add NEW features to the current workflow OR modify the current canvas (keywords: "修改当前工作流", "更新工作流", "在当前工作流中添加", "添加功能", "enhance current workflow", "modify workflow", "add to current workflow", "update current workflow", "添加LoRA", "加个upscale", "add upscaling", "修改当前画布", "更新画布", "在画布中", "modify current canvas", "update canvas", "change canvas"), you MUST handoff to the Workflow Rewrite Agent immediately. This is for feature enhancements, not error fixes. - **ERROR MESSAGE ANALYSIS** - When a user pastes specific error text/logs (containing terms like "Failed", "Error", "Traceback", or stack traces), prioritize providing troubleshooting help rather than invoking search tools. Follow these steps: 1. Analyze the error to identify the root cause (error type, affected component, missing dependencies, etc.) diff --git a/backend/service/parameter_tools.py b/backend/service/parameter_tools.py index f9da7e5..3e004cc 100644 --- a/backend/service/parameter_tools.py +++ b/backend/service/parameter_tools.py @@ -73,34 +73,8 @@ async def find_matching_parameter_value(node_name: str, param_name: str, current "is_file_related": False, } - # 识别model相关错误 - if (any(model_keyword in current_value.lower() for model_keyword in [ - ".ckpt", ".safetensors", ".pt", ".pth", ".bin", "checkpoint", "lora", "vae", "controlnet", "clip", "unet" - ]) or any(model_keyword in param_name.lower() for model_keyword in [ - "model", "checkpoint", "lora", "vae", "clip", "controlnet", "unet" - ]) or any(model_keyword in error_lower for model_keyword in [ - "model not found", "checkpoint", "missing model", "file not found" - ])): - error_analysis["error_type"] = "model_missing" - error_analysis["is_model_related"] = True - - return json.dumps({ - "found_match": False, - "error_type": "model_missing", - "message": f"Missing model file: {current_value}", - "recommendation": "Check for available model replacements, otherwise download required.", - "next_action": "check_available_models_or_suggest_download", - "details": { - "node_name": node_name, - "param_name": param_name, - "missing_file": current_value, - "is_model_related": True, - "param_config": param_config - } - }) - - # 识别image文件相关错误 - elif (any(img_ext in current_value.lower() for img_ext in [".png", ".jpg", ".jpeg", ".bmp", ".tiff", ".webp"]) or + # 优先识别image文件相关错误(在model检测之前,因为image文件可能包含model关键词) + if (any(img_ext in current_value.lower() for img_ext in [".png", ".jpg", ".jpeg", ".bmp", ".tiff", ".webp"]) or param_name.lower() in ["image", "img", "picture", "photo"] or any(img_keyword in error_lower for img_keyword in ["invalid image", "image file", "image not found"])): error_analysis["error_type"] = "image_file_missing" @@ -135,6 +109,32 @@ async def find_matching_parameter_value(node_name: str, param_name: str, current "can_auto_fix": False }) + # 识别model相关错误(在image检测之后) + elif (any(model_keyword in current_value.lower() for model_keyword in [ + ".ckpt", ".safetensors", ".pt", ".pth", ".bin", "checkpoint", "lora", "vae", "controlnet", "clip", "unet" + ]) or any(model_keyword in param_name.lower() for model_keyword in [ + "model", "checkpoint", "lora", "vae", "clip", "controlnet", "unet" + ]) or any(model_keyword in error_lower for model_keyword in [ + "model not found", "checkpoint", "missing model", "file not found" + ])): + error_analysis["error_type"] = "model_missing" + error_analysis["is_model_related"] = True + + return json.dumps({ + "found_match": False, + "error_type": "model_missing", + "message": f"Missing model file: {current_value}", + "recommendation": "Check for available model replacements, otherwise download required.", + "next_action": "check_available_models_or_suggest_download", + "details": { + "node_name": node_name, + "param_name": param_name, + "missing_file": current_value, + "is_model_related": True, + "param_config": param_config + } + }) + # 处理枚举类型的参数(原有逻辑,但增强) elif isinstance(param_config, list) and len(param_config) > 0: available_values = param_config @@ -250,9 +250,6 @@ async def find_matching_parameter_value(node_name: str, param_name: str, current async def get_model_files(model_type: str = "checkpoints") -> str: """获取可用的模型文件列表""" try: - # 获取所有节点信息 - object_info = await get_object_info() - # 定义模型类型到节点的映射 model_type_mapping = { "checkpoints": ["CheckpointLoaderSimple", "CheckpointLoader"], @@ -267,15 +264,36 @@ async def get_model_files(model_type: str = "checkpoints") -> str: # 查找对应的节点 model_files = {} for node_name in model_type_mapping.get(model_type.lower(), []): - if node_name in object_info: - node_info = object_info[node_name] - if 'input' in node_info: + try: + # 使用 get_object_info_by_class 获取单个节点信息,减少数据量 + node_data = await get_object_info_by_class(node_name) + + # 处理不同的返回格式 + node_info = None + if node_name in node_data: + # 格式:{"NodeName": {...}} + node_info = node_data[node_name] + elif 'input' in node_data: + # 格式:直接返回节点信息 {...} + node_info = node_data + + if node_info and 'input' in node_info: # 查找包含文件列表的参数 for input_type in ['required', 'optional']: if input_type in node_info['input']: for param_name, param_config in node_info['input'][input_type].items(): - if isinstance(param_config, tuple) and isinstance(param_config[0], list) and len(param_config[0]) > 0: - model_files[f"{node_name}.{param_name}"] = param_config[0] + # 检查参数配置格式:[file_list, {...}] 或 [file_list] + if isinstance(param_config, list) and len(param_config) > 0: + if isinstance(param_config[0], list) and len(param_config[0]) > 0: + # 检查是否为文件列表(包含文件扩展名或路径) + file_list = param_config[0] + if any(isinstance(item, str) and ('.' in item or '/' in item) for item in file_list): + model_files[f"{node_name}.{param_name}"] = file_list + + except Exception as e: + # 单个节点查询失败,继续处理其他节点 + print(f"Failed to get info for node {node_name}: {e}") + continue if model_files: return json.dumps({ diff --git a/backend/service/workflow_rewrite_agent.py b/backend/service/workflow_rewrite_agent.py index f1d2934..b8b1096 100644 --- a/backend/service/workflow_rewrite_agent.py +++ b/backend/service/workflow_rewrite_agent.py @@ -2,7 +2,7 @@ Author: ai-business-hql qingli.hql@alibaba-inc.com Date: 2025-07-24 17:10:23 LastEditors: ai-business-hql qingli.hql@alibaba-inc.com -LastEditTime: 2025-07-31 11:20:37 +LastEditTime: 2025-08-06 19:32:27 FilePath: /comfyui_copilot/backend/service/workflow_rewrite_agent.py Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE ''' @@ -11,17 +11,57 @@ from agents.tool import function_tool import json import time import uuid +from agents.tool import function_tool +import os +from typing import Dict, Any from ..agent_factory import create_agent from ..utils.globals import get_language from ..service.workflow_rewrite_tools import * +@function_tool +def get_rewrite_expert_by_name(name_list: list[str]) -> str: + """根据经验名称来获取工作流改写专家经验""" + result = "" + with open(os.path.join(os.path.dirname(__file__), "..", "data", "workflow_rewrite_expert.json"), "r") as f: + data = json.load(f) + for name in name_list: + for item in data: + if item["name"] == name: + result += f'### {name}({item["description"]}):\n{item["content"]}\n' + return result -def create_workflow_rewrite_agent(session_id: str): - """创建带有session_id的workflow_rewrite_agent实例""" +def get_rewrite_export_schema() -> dict: + """获取工作流改写专家经验schema""" + expert_schema = [] + with open(os.path.join(os.path.dirname(__file__), "..", "data", "workflow_rewrite_expert.json"), "r") as f: + data = json.load(f) + for item in data: + expert_schema.append({ + "name": item["name"], + "description": item["description"] + }) + return expert_schema + + +def create_workflow_rewrite_agent(session_id: str, config: Dict[str, Any] = None): + """创建带有session_id和config的workflow_rewrite_agent实例""" language = get_language() + # 导入workflow_rewrite_tools并设置配置 + from .workflow_rewrite_tools import get_workflow_data_from_config, update_workflow, remove_node, get_node_info + from ..service.database import get_workflow_data + + # 创建带有配置的工具函数 + @function_tool + def get_current_workflow_with_config(session_id: str) -> str: + """获取当前session的工作流数据""" + workflow_data = get_workflow_data_from_config(config) if config else get_workflow_data(session_id) + if not workflow_data: + return json.dumps({"error": "No workflow data found for this session"}) + return json.dumps(workflow_data) + return create_agent( name="Workflow Rewrite Agent", model="us.anthropic.claude-sonnet-4-20250514-v1:0", @@ -35,809 +75,33 @@ def create_workflow_rewrite_agent(session_id: str): **当前Session ID:** {}""".format(language, session_id) + """ ## 主要处理场景 - - ### 文生图场景优化 - 1. **LoRA集成**:在现有工作流中添加LoRA节点,确保与现有模型和提示词节点正确连接 - 在checkpoint节点后添加LoRA节点。 - { - "1": { - "inputs": { - "lora_name": "DOG.safetensors", - "strength_model": 1, - "strength_clip": 1, - "model": [ - "2", - 0 - ], - "clip": [ - "2", - 1 - ] - }, - "class_type": "LoraLoader", - "_meta": { - "title": "Load LoRA" - } - } - - 在checkpoint节点后添加vae encode节点 - - { - "2": { - "inputs": { - "ckpt_name": "Flux_Kontext_dev_.safetensors" - }, - "class_type": "CheckpointLoaderSimple", - "_meta": { - "title": "Load Checkpoint" - } - }, - "5": { - "inputs": { - "vae": [ - "2", - 2 - ] - }, - "class_type": "VAEEncode", - "_meta": { - "title": "VAE Encode" - } - } -} - - 2. **后处理增强**: - - 在Preview Image或Save Image节点后添加高清放大功能(如Real-ESRGAN、ESRGAN等) - - 添加图像缩放节点 - { - "1": { - "inputs": { - "width": 512, - "height": 512, - "interpolation": "nearest", - "method": "stretch", - "condition": "always", - "multiple_of": 0 - }, - "class_type": "ImageResize+", - "_meta": { - "title": "🔧 Image Resize" - } - } -} - - 添加图像尺寸调整节点 - { - "2": { - "inputs": { - "aspect_ratio": "original", - "proportional_width": 2, - "proportional_height": 1, - "fit": "letterbox", - "method": "lanczos", - "round_to_multiple": "8", - "scale_to_longest_side": false, - "longest_side": 1024 - }, - "class_type": "LayerUtility: ImageScaleByAspectRatio", - "_meta": { - "title": "LayerUtility: ImageScaleByAspectRatio" - } - } -} - -添加图像放大节点 - "11": { - "inputs": { - "width": 512, - "height": 512, - "upscale_method": "nearest-exact", - "keep_proportion": false, - "divisible_by": 2, - "crop": "disabled", - "image": [ - "12", - 0 - ] - }, - "class_type": "ImageResizeKJ", - "_meta": { - "title": "Resize Image" - } - }, - -添加VAEdecode节点 - "12": { - "inputs": {}, - "class_type": "VAEDecode", - "_meta": { - "title": "VAE Decode" - } - } -} - - 3. **提示词优化**: - - 修改现有提示词节点的内容(提示词应该在(CLIP Text Encode Prompt或Text _O节点内编辑) - - 添加单独的提示词输入节点 - { - "12": { - "inputs": { - "text": [ - "13", - 0 - ] - }, - "class_type": "CLIPTextEncode", - "_meta": { - "title": "CLIP Text Encode (Prompt)" - } - }, - "13": { - "inputs": { - "delimiter": ", ", - "clean_whitespace": "true", - "text_a": [ - "15", - 0 - ], - "text_b": [ - "16", - 0 - ] - }, - "class_type": "Text Concatenate", - "_meta": { - "title": "Text Concatenate" - } - }, - "15": { - "inputs": { - "text": "" - }, - "class_type": "Text _O", - "_meta": { - "title": "Text _O" - } - }, - "16": { - "inputs": { - "text": "" - }, - "class_type": "Text _O", - "_meta": { - "title": "Text _O" - } - } -} - - ### 图生图场景优化 - 1. **LoRA增强**:为图生图工作流添加LoRA支持,保证与图像输入节点兼容 - -在checkpoint节点后添加LoRA节点。(与文生图添加lora节点的方式保持一致) - 2. **图像反推功能**: - - 添加图像反推节点(如CLIP Interrogator) -{ - "11": { - "inputs": { - "prompt_mode": "fast", - "image_analysis": "off" - }, - "class_type": "ClipInterrogator", - "_meta": { - "title": "Clip Interrogator ♾️Mixlab" - } - } -} - - 添加更复杂或者更好用的图像反推节点(加载图片使用florence2进行反推) - { - "6": { - "inputs": { - "image": "06.JPG" - }, - "class_type": "LoadImage", - "_meta": { - "title": "$image.image!:The image to analyze, must be a url" - } - }, - "10": { - "inputs": { - "model": "microsoft/Florence-2-large", - "precision": "fp16", - "attention": "sdpa" - }, - "class_type": "DownloadAndLoadFlorence2Model", - "_meta": { - "title": "DownloadAndLoadFlorence2Model" - } - }, - "11": { - "inputs": { - "text_input": "", - "task": "more_detailed_caption", - "fill_mask": true, - "keep_model_loaded": false, - "max_new_tokens": 1024, - "num_beams": 3, - "do_sample": true, - "output_mask_select": "", - "seed": 1098631327477633, - "image": [ - "6", - 0 - ], - "florence2_model": [ - "10", - 0 - ] - }, - "class_type": "Florence2Run", - "_meta": { - "title": "Florence2Run" - } - }, - "18": { - "inputs": { - "anything": [ - "11", - 2 - ] - }, - "class_type": "easy showAnything", - "_meta": { - "title": "Show Any" - } - }, - "20": { - "inputs": { - "value": "Generate high-quality text descriptions from images using local Florence model.\n \n Main use cases:\n 1. **Reverse image prompt generation**:\n - When users upload an image and want to get prompts for AI art generation\n - Analyzes visual elements, style, composition, etc. to generate prompts for Stable Diffusion, DALL-E, and other models\n - In this case, return the tool's raw output directly to users without any modification or summary\n - Users can directly use these prompts for image generation\n 2. **Image content understanding**:\n - When users ask about specific content, objects, scenes, people, etc. in the image\n - Need to understand the semantic content of the image and answer users' specific questions\n - In this case, combine tool output with conversation context to give users contextually appropriate natural responses\n - Don't return raw output directly, but provide targeted replies based on understanding results" - }, - "class_type": "PrimitiveStringMultiline", - "_meta": { - "title": "MCP" - } - } -} - 3. **ControlNet集成**:(preprocessor可选canny、depth等参数,模型样式选择,Controlnet开始、结束权重) - { - "22": { - "inputs": { - "strength": 1, - "start_percent": 0, - "end_percent": 1, - "control_net": [ - "23", - 0 - ], - "image": [ - "24", - 0 - ] - }, - "class_type": "ControlNetApplyAdvanced", - "_meta": { - "title": "Apply ControlNet" - } - }, - "23": { - "inputs": { - "control_net_name": "ControlNet-Standard-Lineart-for-SDXL.safetensors" - }, - "class_type": "ControlNetLoader", - "_meta": { - "title": "Load ControlNet Model" - } - }, - "24": { - "inputs": { - "preprocessor": "none", - "resolution": 512 - }, - "class_type": "AIO_Preprocessor", - "_meta": { - "title": "AIO Aux Preprocessor" - } - } -} - 4. **高级图像处理**: - -给我一个扩图链路(包括图像加载和图像输出) - - 添加图像高清放大链路 - { - "58": { - "inputs": { - "vae_name": "ae.safetensors" - }, - "class_type": "VAELoader", - "_meta": { - "title": "Load VAE" - } - }, - "59": { - "inputs": { - "clip_name1": "t5xxl_fp8_e4m3fn.safetensors", - "clip_name2": "clip_l.safetensors", - "type": "flux", - "device": "default" - }, - "class_type": "DualCLIPLoader", - "_meta": { - "title": "DualCLIPLoader" - } - }, - "60": { - "inputs": { - "unet_name": "F.1-dev-fp8.safetensors", - "weight_dtype": "fp8_e4m3fn" - }, - "class_type": "UNETLoader", - "_meta": { - "title": "Load Diffusion Model" - } - }, - "175": { - "inputs": { - "upscale_by": 2.0000000000000004, - "seed": 203184385867926, - "steps": 10, - "cfg": 3, - "sampler_name": "dpmpp_2m", - "scheduler": "karras", - "denoise": 0.34, - "mode_type": "Linear", - "tile_width": 512, - "tile_height": 512, - "mask_blur": 8, - "tile_padding": 32, - "seam_fix_mode": "None", - "seam_fix_denoise": 1, - "seam_fix_width": 64, - "seam_fix_mask_blur": 8, - "seam_fix_padding": 16, - "force_uniform_tiles": true, - "tiled_decode": false, - "image": [ - "263", - 0 - ], - "model": [ - "266", - 0 - ], - "positive": [ - "267", - 0 - ], - "negative": [ - "271", - 0 - ], - "vae": [ - "269", - 0 - ], - "upscale_model": [ - "270", - 0 - ] - }, - "class_type": "UltimateSDUpscale", - "_meta": { - "title": "Ultimate SD Upscale" - } - }, - "176": { - "inputs": { - "text": [ - "226", - 2 - ], - "clip": [ - "59", - 0 - ] - }, - "class_type": "CLIPTextEncode", - "_meta": { - "title": "CLIP Text Encode (Prompt)" - } - }, - "178": { - "inputs": { - "model_name": "4xNomos8kSCHAT-L.pth" - }, - "class_type": "UpscaleModelLoader", - "_meta": { - "title": "Load Upscale Model" - } - }, - "188": { - "inputs": { - "guidance": 30, - "conditioning": [ - "213", - 0 - ] - }, - "class_type": "FluxGuidance", - "_meta": { - "title": "FluxGuidance" - } - }, - "189": { - "inputs": { - "conditioning": [ - "176", - 0 - ] - }, - "class_type": "ConditioningZeroOut", - "_meta": { - "title": "ConditioningZeroOut" - } - }, - "212": { - "inputs": { - "type": "tile", - "control_net": [ - "214", - 0 - ] - }, - "class_type": "SetUnionControlNetType", - "_meta": { - "title": "SetUnionControlNetType" - } - }, - "213": { - "inputs": { - "strength": 0.30000000000000004, - "start_percent": 0, - "end_percent": 1, - "positive": [ - "176", - 0 - ], - "negative": [ - "189", - 0 - ], - "control_net": [ - "212", - 0 - ], - "image": [ - "215", - 0 - ], - "vae": [ - "58", - 0 - ] - }, - "class_type": "ControlNetApplyAdvanced", - "_meta": { - "title": "Apply ControlNet" - } - }, - "214": { - "inputs": { - "control_net_name": "FLUX.1-dev-ControlNet-Union-Pro.safetensors" - }, - "class_type": "ControlNetLoader", - "_meta": { - "title": "Load ControlNet Model" - } - }, - "215": { - "inputs": { - "preprocessor": "TTPlanet_TileSimple_Preprocessor", - "resolution": [ - "217", - 0 - ], - "image": [ - "272", - 0 - ] - }, - "class_type": "AIO_Preprocessor", - "_meta": { - "title": "AIO Aux Preprocessor" - } - }, - "216": { - "inputs": { - "image": [ - "272", - 0 - ] - }, - "class_type": "GetImageSize+", - "_meta": { - "title": "🔧 Get Image Size" - } - }, - "217": { - "inputs": { - "image_gen_width": [ - "216", - 0 - ], - "image_gen_height": [ - "216", - 1 - ], - "resize_mode": "Just Resize", - "original_image": [ - "272", - 0 - ] - }, - "class_type": "PixelPerfectResolution", - "_meta": { - "title": "Pixel Perfect Resolution" - } - }, - "226": { - "inputs": { - "text_input": "", - "task": "region_caption", - "fill_mask": true, - "keep_model_loaded": false, - "max_new_tokens": 1024, - "num_beams": 3, - "do_sample": true, - "output_mask_select": "", - "seed": 204052510973001, - "image": [ - "272", - 0 - ], - "florence2_model": [ - "227", - 0 - ] - }, - "class_type": "Florence2Run", - "_meta": { - "title": "Florence2Run" - } - }, - "227": { - "inputs": { - "model": "Florence-2-large", - "precision": "fp16", - "attention": "sdpa" - }, - "class_type": "Florence2ModelLoader", - "_meta": { - "title": "Florence2ModelLoader" - } - }, - "230": { - "inputs": { - "text": "home appliance", - "anything": [ - "226", - 2 - ] - }, - "class_type": "easy showAnything", - "_meta": { - "title": "Show Any" - } - }, - "240": { - "inputs": { - "filename_prefix": "ComfyUI", - "images": [ - "175", - 0 - ] - }, - "class_type": "SaveImage", - "_meta": { - "title": "Save Image" - } - }, - "263": { - "inputs": { - "anything": [ - "272", - 0 - ] - }, - "class_type": "easy cleanGpuUsed", - "_meta": { - "title": "Clean VRAM Used" - } - }, - "266": { - "inputs": { - "anything": [ - "60", - 0 - ] - }, - "class_type": "easy cleanGpuUsed", - "_meta": { - "title": "Clean VRAM Used" - } - }, - "267": { - "inputs": { - "anything": [ - "188", - 0 - ] - }, - "class_type": "easy cleanGpuUsed", - "_meta": { - "title": "Clean VRAM Used" - } - }, - "269": { - "inputs": { - "anything": [ - "58", - 0 - ] - }, - "class_type": "easy cleanGpuUsed", - "_meta": { - "title": "Clean VRAM Used" - } - }, - "270": { - "inputs": { - "anything": [ - "178", - 0 - ] - }, - "class_type": "easy cleanGpuUsed", - "_meta": { - "title": "Clean VRAM Used" - } - }, - "271": { - "inputs": { - "anything": [ - "213", - 1 - ] - }, - "class_type": "easy cleanGpuUsed", - "_meta": { - "title": "Clean VRAM Used" - } - }, - "272": { - "inputs": { - "image": "234.png" - }, - "class_type": "LoadImage", - "_meta": { - "title": "Load Image" - } - } -} - - 配置图像缩放和裁剪功能 - { - "46": { - "inputs": { - "width": [ - "47", - 1 - ], - "height": [ - "47", - 2 - ], - "position": "top-left", - "x_offset": 0, - "y_offset": 0, - "image": [ - "47", - 0 - ] - }, - "class_type": "ImageCrop+", - "_meta": { - "title": "🔧 Image Crop" - } - }, - "47": { - "inputs": { - "width": 512, - "height": 512, - "interpolation": "nearest", - "method": "stretch", - "condition": "always", - "multiple_of": 0 - }, - "class_type": "ImageResize+", - "_meta": { - "title": "🔧 Image Resize" - } - }, - "49": { - "inputs": { - "images": [ - "46", - 0 - ] - }, - "class_type": "PreviewImage", - "_meta": { - "title": "Preview Image" - } - } -} - 5. **智能抠图**: - - 添加背景移除节点(如SAM、U²-Net等) - - 添加背景移除或抠图节点 - { - "7": { - "inputs": { - "rem_mode": "RMBG-1.4", - "image_output": "Preview", - "save_prefix": "ComfyUI", - "torchscript_jit": false, - "add_background": "none", - "refine_foreground": false - }, - "class_type": "easy imageRemBg", - "_meta": { - "title": "Image Remove Bg" - } - } -} - - 添加SAM抠图节点 - { - "8": { - "inputs": { - "prompt": "", - "threshold": 0.3, - "sam_model": [ - "9", - 0 - ], - "grounding_dino_model": [ - "10", - 0 - ] - }, - "class_type": "GroundingDinoSAMSegment (segment anything)", - "_meta": { - "title": "GroundingDinoSAMSegment (segment anything)" - } - }, - "9": { - "inputs": { - "model_name": "sam_vit_h (2.56GB)" - }, - "class_type": "SAMModelLoader (segment anything)", - "_meta": { - "title": "SAMModelLoader (segment anything)" - } - }, - "10": { - "inputs": { - "model_name": "GroundingDINO_SwinT_OGC (694MB)" - }, - "class_type": "GroundingDinoModelLoader (segment anything)", - "_meta": { - "title": "GroundingDinoModelLoader (segment anything)" - } - } -} - + {} + """.format(json.dumps(get_rewrite_export_schema())) + """ + 你可以根据用户的需求,从上面的专家经验中选择一个或多个经验,并根据经验内容进行工作流改写。 + ## 操作原则 - **保持兼容性**:确保修改后的工作流与现有节点兼容 - **优化连接**:正确设置节点间的输入输出连接 + - **连线完整性**:修改工作流时必须确保所有节点的连线关系完整,不遗漏任何必要的输入输出连接 + * 检查每个节点的必需输入是否已连接 + * 对于未连接的必需输入,优先寻找类型匹配的现有节点输出进行连接 + * 如果找不到合适的现有输出,则创建适当的输入节点(如常量节点、加载节点等) + * 确保连接的参数类型完全匹配,避免类型不兼容的连接 + - **连线检查**:在添加、删除或修改节点时,务必检查所有相关的输入和输出连接是否正确配置 + - **连接关系维护**:修改节点时必须保持原有的连接逻辑,确保数据流向正确 + - **类型严格匹配**:在进行任何连线操作时,必须严格验证输入输出类型匹配 + * 在修改连线前,先使用get_node_info()获取节点的完整输入输出规格信息 + * 仔细检查源节点的输出类型(output_type)与目标节点的输入类型(input_type) + * 如果类型不匹配,寻找正确的源节点或添加类型转换节点 - **性能考虑**:避免不必要的重复节点,优化工作流执行效率 - **用户友好**:保持工作流结构清晰,便于用户理解和后续修改 - **错误处理**:在修改过程中检查潜在的配置错误,提供修正建议 **Tool Usage Guidelines:** + - get_current_workflow(): Get current workflow from checkpoint or session - remove_node(): Use for incompatible or problematic nodes - update_workflow(): Use to save your changes (ALWAYS call this after fixes) + - get_node_info(): Get detailed node information and verify input/output types before connecting ## 响应格式 @@ -845,7 +109,7 @@ def create_workflow_rewrite_agent(session_id: str): 始终以用户的实际需求为导向,提供专业、准确、高效的工作流改写服务。 """, - tools=[get_current_workflow, get_node_info, update_workflow, remove_node], + tools=[get_rewrite_expert_by_name, get_current_workflow_with_config, get_node_info, update_workflow, remove_node], ) # 保持向后兼容性的默认实例 diff --git a/backend/service/workflow_rewrite_tools.py b/backend/service/workflow_rewrite_tools.py index 8f22441..fe5c10f 100644 --- a/backend/service/workflow_rewrite_tools.py +++ b/backend/service/workflow_rewrite_tools.py @@ -6,10 +6,47 @@ from typing import Dict, Any, Optional, List from agents.agent import Agent from agents.tool import function_tool +from ..utils.string_utils import error_format -from ..service.database import get_workflow_data, save_workflow_data +from ..service.database import get_workflow_data, save_workflow_data, get_workflow_data_ui, get_workflow_data_by_id from ..utils.comfy_gateway import get_object_info +def get_workflow_data_from_config(config: Dict[str, Any]) -> Optional[Dict[str, Any]]: + """获取工作流数据,优先使用checkpoint_id,如果没有则使用session_id""" + workflow_checkpoint_id = config.get('workflow_checkpoint_id') + session_id = config.get('session_id') + + if workflow_checkpoint_id: + try: + checkpoint_data = get_workflow_data_by_id(workflow_checkpoint_id) + if checkpoint_data and checkpoint_data.get('workflow_data'): + return checkpoint_data['workflow_data'] + except Exception as e: + print(f"Failed to get workflow data from checkpoint {workflow_checkpoint_id}: {str(e)}") + + if session_id: + return get_workflow_data(session_id) + + return None + +def get_workflow_data_ui_from_config(config: Dict[str, Any]) -> Optional[Dict[str, Any]]: + """获取工作流UI数据,优先使用checkpoint_id,如果没有则使用session_id""" + workflow_checkpoint_id = config.get('workflow_checkpoint_id') + session_id = config.get('session_id') + + if workflow_checkpoint_id: + try: + checkpoint_data = get_workflow_data_by_id(workflow_checkpoint_id) + if checkpoint_data and checkpoint_data.get('workflow_data_ui'): + return checkpoint_data['workflow_data_ui'] + except Exception as e: + print(f"Failed to get workflow UI data from checkpoint {workflow_checkpoint_id}: {str(e)}") + + if session_id: + return get_workflow_data_ui(session_id) + + return None + @function_tool def get_current_workflow(session_id: str) -> str: """获取当前session的工作流数据""" @@ -47,7 +84,7 @@ def save_checkpoint_before_modification(session_id: str, action_description: str checkpoint_id = save_workflow_data( session_id, current_workflow, - workflow_data_ui=None, # UI format not available in tools + workflow_data_ui=get_workflow_data_ui(session_id), attributes={ "checkpoint_type": "workflow_rewrite_start", "description": f"Checkpoint before {action_description}", @@ -111,7 +148,8 @@ def update_workflow(session_id: str, workflow_data: str) -> str: "ext": ext_data }) except Exception as e: - return json.dumps({"error": f"Failed to update workflow: {str(e)}"}) + print(f"Failed to update workflow: {str(e)}") + return json.dumps({"error": f"Failed to update workflow"}) @function_tool def remove_node(session_id: str, node_id: str) -> str: diff --git a/backend/utils/string_utils.py b/backend/utils/string_utils.py new file mode 100644 index 0000000..eb22fef --- /dev/null +++ b/backend/utils/string_utils.py @@ -0,0 +1,5 @@ +def error_format(e: Exception) -> str: + error_message = str(e).replace('\n', ' ').replace('\r', ' ').replace('\t', ' ') + # 移除可能导致JSON解析错误的控制字符 + error_message = ''.join(char for char in error_message if ord(char) >= 32 or char in '\n\r\t') + return error_message \ No newline at end of file diff --git a/dist/copilot_web/App-C2CSnZyL.js b/dist/copilot_web/App-ZL1eWx5_.js similarity index 87% rename from dist/copilot_web/App-C2CSnZyL.js rename to dist/copilot_web/App-ZL1eWx5_.js index 1298bc3..990daf5 100644 --- a/dist/copilot_web/App-C2CSnZyL.js +++ b/dist/copilot_web/App-ZL1eWx5_.js @@ -1,7 +1,7 @@ function getImportPath(filename) { return `./${filename}`; } - const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/workflowChat-CSy2RX18.js","copilot_web/vendor-markdown-BAJQc3l1.js","copilot_web/vendor-react-Dixhfmvb.js","copilot_web/message-components-Cf5ztmsp.js","copilot_web/input.js","copilot_web/assets/input-BDTaXBTQ.css","copilot_web/fonts.css"].map(path => { + const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/workflowChat-BGZdyRxi.js","copilot_web/vendor-markdown-BAJQc3l1.js","copilot_web/vendor-react-Dixhfmvb.js","copilot_web/message-components-DPTrVTCp.js","copilot_web/input.js","copilot_web/assets/input-BDTaXBTQ.css","copilot_web/fonts.css"].map(path => { const apiBase = window.comfyAPI?.api?.api?.api_base; if (apiBase) { // 有 API base 时,使用完整路径 @@ -11,4 +11,4 @@ function getImportPath(filename) { return `./${path}`; } }))))=>i.map(i=>d[i]); -import{_ as a}from"./input.js";import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{r as t,R as i}from"./vendor-react-Dixhfmvb.js";import{C as n}from"./message-components-Cf5ztmsp.js";const s={EXPLAIN_NODE:"copilot:explain-node",TOOLBOX_USAGE:"copilot:toolbox-usage",TOOLBOX_PARAMETERS:"copilot:toolbox-parameters",TOOLBOX_DOWNSTREAMNODES:"copilot:toolbox-downstreamnodes"},d=i.lazy(()=>a(()=>import(getImportPath("workflowChat-CSy2RX18.js")),__vite__mapDeps([0,1,2,3,4,5,6])).then(o=>({default:o.default})));function c(){const[o,r]=t.useState(!1);return t.useEffect(()=>{const l=()=>{r(!0)};return window.addEventListener(s.EXPLAIN_NODE,l),()=>window.removeEventListener(s.EXPLAIN_NODE,l)},[]),e.jsx(n,{children:e.jsx("div",{className:"h-full w-full flex flex-col",children:e.jsx(t.Suspense,{fallback:e.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:e.jsx(d,{visible:!0,triggerUsage:o,onUsageTriggered:()=>r(!1)})})})})}const O=Object.freeze(Object.defineProperty({__proto__:null,default:c},Symbol.toStringTag,{value:"Module"}));export{O as A,s as C}; +import{_ as a}from"./input.js";import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{r as t,R as i}from"./vendor-react-Dixhfmvb.js";import{C as n}from"./message-components-DPTrVTCp.js";const s={EXPLAIN_NODE:"copilot:explain-node",TOOLBOX_USAGE:"copilot:toolbox-usage",TOOLBOX_PARAMETERS:"copilot:toolbox-parameters",TOOLBOX_DOWNSTREAMNODES:"copilot:toolbox-downstreamnodes"},d=i.lazy(()=>a(()=>import(getImportPath("workflowChat-BGZdyRxi.js")),__vite__mapDeps([0,1,2,3,4,5,6])).then(o=>({default:o.default})));function c(){const[o,r]=t.useState(!1);return t.useEffect(()=>{const l=()=>{r(!0)};return window.addEventListener(s.EXPLAIN_NODE,l),()=>window.removeEventListener(s.EXPLAIN_NODE,l)},[]),e.jsx(n,{children:e.jsx("div",{className:"h-full w-full flex flex-col",children:e.jsx(t.Suspense,{fallback:e.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:e.jsx(d,{visible:!0,triggerUsage:o,onUsageTriggered:()=>r(!1)})})})})}const O=Object.freeze(Object.defineProperty({__proto__:null,default:c},Symbol.toStringTag,{value:"Module"}));export{O as A,s as C}; diff --git a/dist/copilot_web/DebugGuide-nVo3jJ10.js b/dist/copilot_web/DebugGuide-CJ_YeVvl.js similarity index 98% rename from dist/copilot_web/DebugGuide-nVo3jJ10.js rename to dist/copilot_web/DebugGuide-CJ_YeVvl.js index 5f5acec..0864bb4 100644 --- a/dist/copilot_web/DebugGuide-nVo3jJ10.js +++ b/dist/copilot_web/DebugGuide-CJ_YeVvl.js @@ -1,5 +1,5 @@ function getImportPath(filename) { return `./${filename}`; } - import{j as r}from"./vendor-markdown-BAJQc3l1.js";import{r as a}from"./vendor-react-Dixhfmvb.js";import{B as I,R as E,h as f,a as h,W as x}from"./message-components-Cf5ztmsp.js";function B({content:g,name:m="Assistant",avatar:A,onAddMessage:b,onUpdateMessage:c,onFinishLoad:k,messageId:y}){const[d,_]=a.useState(!1),[D,O]=a.useState(""),[J,w]=a.useState(!1),[S,v]=a.useState(null);a.useEffect(()=>{k?.()},[]);const s=a.useMemo(()=>{try{return JSON.parse(g)}catch(e){return console.error("Failed to parse message content:",e),null}},[g]),p=a.useMemo(()=>{if(!s||!s.ext)return null;const e=s.ext.find(t=>t.type==="debug_start_checkpoint"||t.type==="debug_checkpoint"&&t.data?.checkpoint_type==="debug_start");return e&&e.data&&e.data.checkpoint_id?e.data.checkpoint_id:null},[s])||S,j=async()=>{if(d)return;const e=f(),t={id:e,role:"ai",content:JSON.stringify({text:`🔍 Starting workflow analysis... + import{j as r}from"./vendor-markdown-BAJQc3l1.js";import{r as a}from"./vendor-react-Dixhfmvb.js";import{B as I,R as E,h as f,a as h,W as x}from"./message-components-DPTrVTCp.js";function B({content:g,name:m="Assistant",avatar:A,onAddMessage:b,onUpdateMessage:c,onFinishLoad:k,messageId:y}){const[d,_]=a.useState(!1),[D,O]=a.useState(""),[J,w]=a.useState(!1),[S,v]=a.useState(null);a.useEffect(()=>{k?.()},[]);const s=a.useMemo(()=>{try{return JSON.parse(g)}catch(e){return console.error("Failed to parse message content:",e),null}},[g]),p=a.useMemo(()=>{if(!s||!s.ext)return null;const e=s.ext.find(t=>t.type==="debug_start_checkpoint"||t.type==="debug_checkpoint"&&t.data?.checkpoint_type==="debug_start");return e&&e.data&&e.data.checkpoint_id?e.data.checkpoint_id:null},[s])||S,j=async()=>{if(d)return;const e=f(),t={id:e,role:"ai",content:JSON.stringify({text:`🔍 Starting workflow analysis... `,ext:[]}),format:"markdown",name:"Assistant",finished:!1,debugGuide:!0};b?.(t);try{await N(),await C(e)}finally{_(!1)}},N=async()=>{try{const e=await h.graphToPrompt(),t=localStorage.getItem("sessionId")||"";if(t&&e){const o=await x.saveWorkflowCheckpoint(t,e.output,e.workflow,"debug_start");if(v(o.version_id),console.log(`Saved debug start checkpoint: ${o.version_id}`),c&&s){const n=[...s.ext||[]].filter(u=>u.type!=="debug_start_checkpoint"&&!(u.type==="debug_checkpoint"&&u.data?.checkpoint_type==="debug_start"));n.push({type:"debug_start_checkpoint",data:{checkpoint_id:o.version_id,checkpoint_type:"debug_start"}});const l={id:y||f(),role:"ai",content:JSON.stringify({text:s.text,ext:n}),format:"debug_guide",name:"Assistant"};c(l)}}}catch(e){console.error("Failed to save checkpoint before debug:",e)}},C=async e=>{try{const t=await h.graphToPrompt();let o="",i=null;for await(const n of x.streamDebugAgent(t))if(n.text){o=n.text,n.ext&&(i=n.ext);const l={id:e,role:"ai",content:JSON.stringify({text:o,ext:i||[]}),format:"markdown",name:"Assistant",finished:!1,debugGuide:!0};c?.(l)}c?.({id:e,role:"ai",content:JSON.stringify({text:o,ext:i||[]}),format:"markdown",name:"Assistant",finished:!0,debugGuide:!0})}catch(t){console.error("Error calling debug agent:",t),w(!1);const i={id:e,role:"ai",content:JSON.stringify({text:`I encountered an error while analyzing your workflow: ${t.message||"Unknown error"}`,ext:[]}),format:"markdown",name:"Assistant",finished:!0};c?.(i)}};return s?r.jsx(I,{name:m,children:r.jsxs("div",{className:"bg-gray-100 pt-4 px-4 pb-3 rounded-lg",children:[r.jsx("div",{className:"flex justify-between items-start",children:r.jsx("p",{className:"text-gray-700 text-sm flex-1",children:s.text})}),r.jsx("div",{className:"flex justify-end mt-4",children:r.jsx("button",{onClick:j,disabled:d,className:`px-4 py-2 text-[#fff] text-sm rounded-md shadow-[0_2px_8px_rbga(79, 140, 255, 0.15)] hover:!shadow-[0_4px_16px_rbga(79, 140, 255, 0.25)] hover:!scale-[1.05] transition-colors ${d?"bg-gray-400 cursor-not-allowed":"bg-debug-btn hover:!bg-debug-btn-hover"}`,children:d?"Analyzing...":"Debug Errors"})}),r.jsx("div",{className:"flex justify-end mt-2",children:!!p&&r.jsx("div",{className:"ml-2 flex-shrink-0",children:r.jsx(E,{checkpointId:p,onRestore:()=>{console.log("Workflow restored from checkpoint")}})})})]})}):null}export{B as DebugGuide}; diff --git a/dist/copilot_web/DebugResult-CCTvL-J7.js b/dist/copilot_web/DebugResult-C18pxqgx.js similarity index 97% rename from dist/copilot_web/DebugResult-CCTvL-J7.js rename to dist/copilot_web/DebugResult-C18pxqgx.js index 338d324..f8f052a 100644 --- a/dist/copilot_web/DebugResult-CCTvL-J7.js +++ b/dist/copilot_web/DebugResult-C18pxqgx.js @@ -1,4 +1,4 @@ function getImportPath(filename) { return `./${filename}`; } - import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{b as u,c as w,B as g,R as k}from"./message-components-Cf5ztmsp.js";import{r as x}from"./vendor-react-Dixhfmvb.js";const v=i=>{const{title:a="",isWorkflowUpdate:p=!1,className:c="",onFinishLoad:d,children:f}=i,[n,s]=x.useState(!1);return x.useEffect(()=>{d?.()},[]),e.jsxs("div",{className:`relative rounded-lg flex flex-col debug-collapsible-card ${c} ${n?"":"h-[200px]"}`,children:[e.jsx("div",{className:"card-border rounded-lg"}),e.jsxs("div",{className:"flex flex-1 justify-between items-center pb-2 border-b border-[#29292f]",children:[e.jsx("div",{children:typeof a=="string"?e.jsx("h3",{className:"text-sm text-[#fff] font-medium",children:a}):a}),e.jsx("button",{onClick:()=>{s(!n)},children:n?e.jsx(u,{color:"#E5E7EB"}):e.jsx(w,{color:"#E5E7EB"})})]}),e.jsx("div",{className:"overflow-hidden",children:f})]})};function y({content:i,name:a="Assistant",avatar:p,format:c="markdown",onFinishLoad:d}){const f=s=>c==="markdown"?s.replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").replace(/`(.*?)`/g,'$1').replace(/\n/g,"
"):s,n=()=>{let s=null,r=!1,o;try{if(o=JSON.parse(i),o.ext){let t=o.ext.find(l=>l.type==="workflow_rewrite_checkpoint"||l.type==="debug_checkpoint"&&l.data?.checkpoint_type==="workflow_rewrite_start");t&&t.data&&t.data.checkpoint_id?(s=t.data.checkpoint_id,r=!0):(t=o.ext.find(l=>l.type==="workflow_rewrite_complete"),t&&t.data&&t.data.version_id?(s=t.data.version_id,r=!0):(t=o.ext.find(l=>l.type==="debug_checkpoint"),t&&t.data&&t.data.checkpoint_id&&(s=t.data.checkpoint_id,r=!1))),o.ext.find(l=>l.type==="workflow_update")&&(r=!0)}}catch(t){return console.error("Failed to parse DebugResult content:",t),null}const h=r?e.jsxs("div",{className:"flex items-center text-green-500",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",fill:"currentColor",viewBox:"0 0 20 20",children:e.jsx("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",clipRule:"evenodd"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Successfully"})]}):e.jsxs("div",{className:"flex items-center text-[#fff]",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg","p-id":"28108",fill:"currentColor",children:e.jsx("path",{d:"M401.048025 844.855924c0 20.341281 16.643052 36.984333 36.984333 36.984333l147.936307 0c20.341281 0 36.984333-16.643052 36.984333-36.984333L622.952998 807.872614 401.048025 807.872614 401.048025 844.855924zM512 142.159744c-142.943596 0-258.888282 115.944686-258.888282 258.888282 0 88.021729 44.011376 165.503405 110.951975 212.288964l0 83.58365c0 20.341281 16.643052 36.984333 36.984333 36.984333l221.903949 0c20.341281 0 36.984333-16.643052 36.984333-36.984333l0-83.58365c66.941622-46.784536 110.951975-124.266212 110.951975-212.288964C770.888282 258.104429 654.943596 142.159744 512 142.159744zM617.588827 552.682561l-31.621185 22.005176 0 85.248569L438.031335 659.936307l0-85.063351L406.41015 552.866756c-49.743938-34.764781-79.33079-91.350544-79.33079-151.634536 0-101.890598 83.029018-184.92064 184.92064-184.92064s184.92064 83.029018 184.92064 184.92064C696.919617 461.332017 667.332764 517.91778 617.588827 552.682561z","p-id":"28277"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Finished"})]}),m=r?e.jsx("div",{className:"mt-3 text-xs text-gray-700",children:"💡 If you're not satisfied with the changes, click the restore button to revert to the previous version."}):null;return e.jsxs("div",{className:"sticky top-0 left-0 w-full bg-gray-100 p-4 rounded-lg overflow-hidden",children:[e.jsx(v,{title:h,isWorkflowUpdate:r,className:"p-4",onFinishLoad:d,children:e.jsxs("div",{className:"prose prose-sm max-w-none",children:[c==="markdown"?e.jsx("div",{className:"text-[#fff]/70 text-sm leading-relaxed h-full",dangerouslySetInnerHTML:{__html:f(o?.text||"")}}):e.jsx("pre",{className:"whitespace-pre-wrap text-[#fff]/70 text-sm leading-relaxed h-full",children:o?.text||""}),m]})}),e.jsx("div",{className:"flex justify-end mt-2",children:!!s&&e.jsx("div",{className:"ml-2 flex-shrink-0",children:e.jsx(k,{checkpointId:s,onRestore:()=>{console.log(`Workflow restored from ${r?"workflow update":"debug"} checkpoint`)},title:r?`Restore to this version (Version ${s})`:`Restore checkpoint ${s}`})})})]})};return e.jsx(g,{name:a,children:n()})}export{y as DebugResult}; + import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{b as u,c as w,B as g,R as k}from"./message-components-DPTrVTCp.js";import{r as x}from"./vendor-react-Dixhfmvb.js";const v=i=>{const{title:a="",isWorkflowUpdate:p=!1,className:c="",onFinishLoad:d,children:f}=i,[n,s]=x.useState(!1);return x.useEffect(()=>{d?.()},[]),e.jsxs("div",{className:`relative rounded-lg flex flex-col debug-collapsible-card ${c} ${n?"":"h-[200px]"}`,children:[e.jsx("div",{className:"card-border rounded-lg"}),e.jsxs("div",{className:"flex flex-1 justify-between items-center pb-2 border-b border-[#29292f]",children:[e.jsx("div",{children:typeof a=="string"?e.jsx("h3",{className:"text-sm text-[#fff] font-medium",children:a}):a}),e.jsx("button",{onClick:()=>{s(!n)},children:n?e.jsx(u,{color:"#E5E7EB"}):e.jsx(w,{color:"#E5E7EB"})})]}),e.jsx("div",{className:"overflow-hidden",children:f})]})};function y({content:i,name:a="Assistant",avatar:p,format:c="markdown",onFinishLoad:d}){const f=s=>c==="markdown"?s.replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").replace(/`(.*?)`/g,'$1').replace(/\n/g,"
"):s,n=()=>{let s=null,r=!1,o;try{if(o=JSON.parse(i),o.ext){let t=o.ext.find(l=>l.type==="workflow_rewrite_checkpoint"||l.type==="debug_checkpoint"&&l.data?.checkpoint_type==="workflow_rewrite_start");t&&t.data&&t.data.checkpoint_id?(s=t.data.checkpoint_id,r=!0):(t=o.ext.find(l=>l.type==="workflow_rewrite_complete"),t&&t.data&&t.data.version_id?(s=t.data.version_id,r=!0):(t=o.ext.find(l=>l.type==="debug_checkpoint"),t&&t.data&&t.data.checkpoint_id&&(s=t.data.checkpoint_id,r=!1))),o.ext.find(l=>l.type==="workflow_update")&&(r=!0)}}catch(t){return console.error("Failed to parse DebugResult content:",t),null}const h=r?e.jsxs("div",{className:"flex items-center text-green-500",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",fill:"currentColor",viewBox:"0 0 20 20",children:e.jsx("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",clipRule:"evenodd"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Successfully"})]}):e.jsxs("div",{className:"flex items-center text-[#fff]",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg","p-id":"28108",fill:"currentColor",children:e.jsx("path",{d:"M401.048025 844.855924c0 20.341281 16.643052 36.984333 36.984333 36.984333l147.936307 0c20.341281 0 36.984333-16.643052 36.984333-36.984333L622.952998 807.872614 401.048025 807.872614 401.048025 844.855924zM512 142.159744c-142.943596 0-258.888282 115.944686-258.888282 258.888282 0 88.021729 44.011376 165.503405 110.951975 212.288964l0 83.58365c0 20.341281 16.643052 36.984333 36.984333 36.984333l221.903949 0c20.341281 0 36.984333-16.643052 36.984333-36.984333l0-83.58365c66.941622-46.784536 110.951975-124.266212 110.951975-212.288964C770.888282 258.104429 654.943596 142.159744 512 142.159744zM617.588827 552.682561l-31.621185 22.005176 0 85.248569L438.031335 659.936307l0-85.063351L406.41015 552.866756c-49.743938-34.764781-79.33079-91.350544-79.33079-151.634536 0-101.890598 83.029018-184.92064 184.92064-184.92064s184.92064 83.029018 184.92064 184.92064C696.919617 461.332017 667.332764 517.91778 617.588827 552.682561z","p-id":"28277"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Finished"})]}),m=r?e.jsx("div",{className:"mt-3 text-xs text-gray-700",children:"💡 If you're not satisfied with the changes, click the restore button to revert to the previous version."}):null;return e.jsxs("div",{className:"sticky top-0 left-0 w-full bg-gray-100 p-4 rounded-lg overflow-hidden",children:[e.jsx(v,{title:h,isWorkflowUpdate:r,className:"p-4",onFinishLoad:d,children:e.jsxs("div",{className:"prose prose-sm max-w-none",children:[c==="markdown"?e.jsx("div",{className:"text-[#fff]/70 text-sm leading-relaxed h-full",dangerouslySetInnerHTML:{__html:f(o?.text||"")}}):e.jsx("pre",{className:"whitespace-pre-wrap text-[#fff]/70 text-sm leading-relaxed h-full",children:o?.text||""}),m]})}),e.jsx("div",{className:"flex justify-end mt-2",children:!!s&&e.jsx("div",{className:"ml-2 flex-shrink-0",children:e.jsx(k,{checkpointId:s,onRestore:()=>{console.log(`Workflow restored from ${r?"workflow update":"debug"} checkpoint`)},title:r?`Restore to this version (Version ${s})`:`Restore checkpoint ${s}`})})})]})};return e.jsx(g,{name:a,children:n()})}export{y as DebugResult}; diff --git a/dist/copilot_web/WorkflowOption-BXMoNmz0.js b/dist/copilot_web/WorkflowOption-DGm083sa.js similarity index 99% rename from dist/copilot_web/WorkflowOption-BXMoNmz0.js rename to dist/copilot_web/WorkflowOption-DGm083sa.js index c8c4151..d8869b9 100644 --- a/dist/copilot_web/WorkflowOption-BXMoNmz0.js +++ b/dist/copilot_web/WorkflowOption-DGm083sa.js @@ -1,7 +1,7 @@ function getImportPath(filename) { return `./${filename}`; } - import{j as ue}from"./vendor-markdown-BAJQc3l1.js";import{W as Si,h as Ba,a as Bt}from"./message-components-Cf5ztmsp.js";import{g as _u,R as Oe,b as Wa,r as g,d as Ca,a as Ou}from"./vendor-react-Dixhfmvb.js";var ns={exports:{}};/*! + import{j as ue}from"./vendor-markdown-BAJQc3l1.js";import{W as Si,h as Ba,a as Bt}from"./message-components-DPTrVTCp.js";import{g as _u,R as Oe,b as Wa,r as g,d as Ca,a as Ou}from"./vendor-react-Dixhfmvb.js";var ns={exports:{}};/*! Copyright (c) 2018 Jed Watson. Licensed under the MIT License (MIT), see http://jedwatson.github.io/classnames diff --git a/dist/copilot_web/input.js b/dist/copilot_web/input.js index 2309e88..9afd653 100644 --- a/dist/copilot_web/input.js +++ b/dist/copilot_web/input.js @@ -1,7 +1,7 @@ function getImportPath(filename) { return `./${filename}`; } - const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/App-C2CSnZyL.js","copilot_web/vendor-markdown-BAJQc3l1.js","copilot_web/vendor-react-Dixhfmvb.js","copilot_web/message-components-Cf5ztmsp.js"].map(path => { + const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/App-ZL1eWx5_.js","copilot_web/vendor-markdown-BAJQc3l1.js","copilot_web/vendor-react-Dixhfmvb.js","copilot_web/message-components-DPTrVTCp.js"].map(path => { const apiBase = window.comfyAPI?.api?.api?.api_base; if (apiBase) { // 有 API base 时,使用完整路径 @@ -11,7 +11,7 @@ function getImportPath(filename) { return `./${path}`; } }))))=>i.map(i=>d[i]); -import{j as Fu}from"./vendor-markdown-BAJQc3l1.js";import{r as d0,a as Pv,g as ly,R as s0}from"./vendor-react-Dixhfmvb.js";import{w as ay,a as ty}from"./message-components-Cf5ztmsp.js";/* empty css */const uy="modulepreload",ey=function(l){return"/"+l},Jc={},ny=function(a,t,u){let e=Promise.resolve();if(t&&t.length>0){document.getElementsByTagName("link");const f=document.querySelector("meta[property=csp-nonce]"),c=f?.nonce||f?.getAttribute("nonce");e=Promise.allSettled(t.map(i=>{if(i=ey(i),i in Jc)return;Jc[i]=!0;const h=i.endsWith(".css"),b=h?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${i}"]${b}`))return;const S=document.createElement("link");if(S.rel=h?"stylesheet":uy,h||(S.as="script"),S.crossOrigin="",S.href=i,c&&S.setAttribute("nonce",c),document.head.appendChild(S),h)return new Promise((d,m)=>{S.addEventListener("load",d),S.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${i}`)))})}))}function n(f){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=f,window.dispatchEvent(c),!c.defaultPrevented)throw f}return e.then(f=>{for(const c of f||[])c.status==="rejected"&&n(c.reason);return a().catch(n)})};var m0={exports:{}},an={},S0={exports:{}},b0={};/** +import{j as Fu}from"./vendor-markdown-BAJQc3l1.js";import{r as d0,a as Pv,g as ly,R as s0}from"./vendor-react-Dixhfmvb.js";import{w as ay,a as ty}from"./message-components-DPTrVTCp.js";/* empty css */const uy="modulepreload",ey=function(l){return"/"+l},Jc={},ny=function(a,t,u){let e=Promise.resolve();if(t&&t.length>0){document.getElementsByTagName("link");const f=document.querySelector("meta[property=csp-nonce]"),c=f?.nonce||f?.getAttribute("nonce");e=Promise.allSettled(t.map(i=>{if(i=ey(i),i in Jc)return;Jc[i]=!0;const h=i.endsWith(".css"),b=h?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${i}"]${b}`))return;const S=document.createElement("link");if(S.rel=h?"stylesheet":uy,h||(S.as="script"),S.crossOrigin="",S.href=i,c&&S.setAttribute("nonce",c),document.head.appendChild(S),h)return new Promise((d,m)=>{S.addEventListener("load",d),S.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${i}`)))})}))}function n(f){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=f,window.dispatchEvent(c),!c.defaultPrevented)throw f}return e.then(f=>{for(const c of f||[])c.status==="rejected"&&n(c.reason);return a().catch(n)})};var m0={exports:{}},an={},S0={exports:{}},b0={};/** * @license React * scheduler.production.js * @@ -35,4 +35,4 @@ import{j as Fu}from"./vendor-markdown-BAJQc3l1.js";import{r as d0,a as Pv,g as l `+i[u].replace(" at new "," at ");return l.displayName&&b.includes("")&&(b=b.replace("",l.displayName)),b}while(1<=u&&0<=e);break}}}finally{Mn=!1,Error.prepareStackTrace=t}return(t=l?l.displayName||l.name:"")?ft(t):""}function Ny(l){switch(l.tag){case 26:case 27:case 5:return ft(l.type);case 16:return ft("Lazy");case 13:return ft("Suspense");case 19:return ft("SuspenseList");case 0:case 15:return Dn(l.type,!1);case 11:return Dn(l.type.render,!1);case 1:return Dn(l.type,!0);case 31:return ft("Activity");default:return""}}function Ic(l){try{var a="";do a+=Ny(l),l=l.return;while(l);return a}catch(t){return` Error generating stack: `+t.message+` `+t.stack}}function Rl(l){switch(typeof l){case"bigint":case"boolean":case"number":case"string":case"undefined":return l;case"object":return l;default:return""}}function Y0(l){var a=l.type;return(l=l.nodeName)&&l.toLowerCase()==="input"&&(a==="checkbox"||a==="radio")}function qy(l){var a=Y0(l)?"checked":"value",t=Object.getOwnPropertyDescriptor(l.constructor.prototype,a),u=""+l[a];if(!l.hasOwnProperty(a)&&typeof t<"u"&&typeof t.get=="function"&&typeof t.set=="function"){var e=t.get,n=t.set;return Object.defineProperty(l,a,{configurable:!0,get:function(){return e.call(this)},set:function(f){u=""+f,n.call(this,f)}}),Object.defineProperty(l,a,{enumerable:t.enumerable}),{getValue:function(){return u},setValue:function(f){u=""+f},stopTracking:function(){l._valueTracker=null,delete l[a]}}}}function Ne(l){l._valueTracker||(l._valueTracker=qy(l))}function X0(l){if(!l)return!1;var a=l._valueTracker;if(!a)return!0;var t=a.getValue(),u="";return l&&(u=Y0(l)?l.checked?"true":"false":l.value),l=u,l!==t?(a.setValue(l),!0):!1}function qe(l){if(l=l||(typeof document<"u"?document:void 0),typeof l>"u")return null;try{return l.activeElement||l.body}catch{return l.body}}var Ry=/[\n"\\]/g;function Xl(l){return l.replace(Ry,function(a){return"\\"+a.charCodeAt(0).toString(16)+" "})}function yf(l,a,t,u,e,n,f,c){l.name="",f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"?l.type=f:l.removeAttribute("type"),a!=null?f==="number"?(a===0&&l.value===""||l.value!=a)&&(l.value=""+Rl(a)):l.value!==""+Rl(a)&&(l.value=""+Rl(a)):f!=="submit"&&f!=="reset"||l.removeAttribute("value"),a!=null?hf(l,f,Rl(a)):t!=null?hf(l,f,Rl(t)):u!=null&&l.removeAttribute("value"),e==null&&n!=null&&(l.defaultChecked=!!n),e!=null&&(l.checked=e&&typeof e!="function"&&typeof e!="symbol"),c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?l.name=""+Rl(c):l.removeAttribute("name")}function G0(l,a,t,u,e,n,f,c){if(n!=null&&typeof n!="function"&&typeof n!="symbol"&&typeof n!="boolean"&&(l.type=n),a!=null||t!=null){if(!(n!=="submit"&&n!=="reset"||a!=null))return;t=t!=null?""+Rl(t):"",a=a!=null?""+Rl(a):t,c||a===l.value||(l.value=a),l.defaultValue=a}u=u??e,u=typeof u!="function"&&typeof u!="symbol"&&!!u,l.checked=c?l.checked:!!u,l.defaultChecked=!!u,f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"&&(l.name=f)}function hf(l,a,t){a==="number"&&qe(l.ownerDocument)===l||l.defaultValue===""+t||(l.defaultValue=""+t)}function Et(l,a,t,u){if(l=l.options,a){a={};for(var e=0;e"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),sf=!1;if(ca)try{var wt={};Object.defineProperty(wt,"passive",{get:function(){sf=!0}}),window.addEventListener("test",wt,wt),window.removeEventListener("test",wt,wt)}catch{sf=!1}var Ea=null,ec=null,me=null;function V0(){if(me)return me;var l,a=ec,t=a.length,u,e="value"in Ea?Ea.value:Ea.textContent,n=e.length;for(l=0;l=eu),ni=" ",fi=!1;function C0(l,a){switch(l){case"keyup":return nh.indexOf(a.keyCode)!==-1;case"keydown":return a.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function p0(l){return l=l.detail,typeof l=="object"&&"data"in l?l.data:null}var st=!1;function ch(l,a){switch(l){case"compositionend":return p0(a);case"keypress":return a.which!==32?null:(fi=!0,ni);case"textInput":return l=a.data,l===ni&&fi?null:l;default:return null}}function ih(l,a){if(st)return l==="compositionend"||!fc&&C0(l,a)?(l=V0(),me=ec=Ea=null,st=!1,l):null;switch(l){case"paste":return null;case"keypress":if(!(a.ctrlKey||a.altKey||a.metaKey)||a.ctrlKey&&a.altKey){if(a.char&&1=a)return{node:t,offset:a-l};l=u}l:{for(;t;){if(t.nextSibling){t=t.nextSibling;break l}t=t.parentNode}t=void 0}t=hi(t)}}function w0(l,a){return l&&a?l===a?!0:l&&l.nodeType===3?!1:a&&a.nodeType===3?w0(l,a.parentNode):"contains"in l?l.contains(a):l.compareDocumentPosition?!!(l.compareDocumentPosition(a)&16):!1:!1}function W0(l){l=l!=null&&l.ownerDocument!=null&&l.ownerDocument.defaultView!=null?l.ownerDocument.defaultView:window;for(var a=qe(l.document);a instanceof l.HTMLIFrameElement;){try{var t=typeof a.contentWindow.location.href=="string"}catch{t=!1}if(t)l=a.contentWindow;else break;a=qe(l.document)}return a}function cc(l){var a=l&&l.nodeName&&l.nodeName.toLowerCase();return a&&(a==="input"&&(l.type==="text"||l.type==="search"||l.type==="tel"||l.type==="url"||l.type==="password")||a==="textarea"||l.contentEditable==="true")}var bh=ca&&"documentMode"in document&&11>=document.documentMode,mt=null,mf=null,fu=null,Sf=!1;function si(l,a,t){var u=t.window===t?t.document:t.nodeType===9?t:t.ownerDocument;Sf||mt==null||mt!==qe(u)||(u=mt,"selectionStart"in u&&cc(u)?u={start:u.selectionStart,end:u.selectionEnd}:(u=(u.ownerDocument&&u.ownerDocument.defaultView||window).getSelection(),u={anchorNode:u.anchorNode,anchorOffset:u.anchorOffset,focusNode:u.focusNode,focusOffset:u.focusOffset}),fu&&Tu(fu,u)||(fu=u,u=We(mf,"onSelect"),0>=f,e-=f,aa=1<<32-Ol(a)+e|t<n?n:8;var f=O.T,c={};O.T=c,_c(l,!1,a,t);try{var i=e(),h=O.S;if(h!==null&&h(c,i),i!==null&&typeof i=="object"&&typeof i.then=="function"){var b=Oh(i,u);du(l,a,b,Ul(l))}else du(l,a,u,Ul(l))}catch(S){du(l,a,{then:function(){},status:"rejected",reason:S},Ul())}finally{Q.p=n,O.T=f}}function qh(){}function _f(l,a,t,u){if(l.tag!==5)throw Error(o(476));var e=Y1(l).queue;B1(l,e,a,pa,t===null?qh:function(){return X1(l),t(u)})}function Y1(l){var a=l.memoizedState;if(a!==null)return a;a={memoizedState:pa,baseState:pa,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ia,lastRenderedState:pa},next:null};var t={};return a.next={memoizedState:t,baseState:t,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ia,lastRenderedState:t},next:null},l.memoizedState=a,l=l.alternate,l!==null&&(l.memoizedState=a),a}function X1(l){var a=Y1(l).next.queue;du(l,a,{},Ul())}function Hc(){return sl(_u)}function G1(){return ll().memoizedState}function Q1(){return ll().memoizedState}function Rh(l){for(var a=l.return;a!==null;){switch(a.tag){case 24:case 3:var t=Ul();l=Ua(t);var u=Ha(a,l,t);u!==null&&(Hl(u,a,t),vu(u,a,t)),a={cache:sc()},l.payload=a;return}a=a.return}}function Bh(l,a,t){var u=Ul();t={lane:u,revertLane:0,action:t,hasEagerState:!1,eagerState:null,next:null},dn(l)?x1(a,t):(t=vc(l,a,t,u),t!==null&&(Hl(t,l,u),j1(t,a,u)))}function Z1(l,a,t){var u=Ul();du(l,a,t,u)}function du(l,a,t,u){var e={lane:u,revertLane:0,action:t,hasEagerState:!1,eagerState:null,next:null};if(dn(l))x1(a,e);else{var n=l.alternate;if(l.lanes===0&&(n===null||n.lanes===0)&&(n=a.lastRenderedReducer,n!==null))try{var f=a.lastRenderedState,c=n(f,t);if(e.hasEagerState=!0,e.eagerState=c,_l(c,f))return cn(l,a,e,0),C===null&&fn(),!1}catch{}finally{}if(t=vc(l,a,e,u),t!==null)return Hl(t,l,u),j1(t,a,u),!0}return!1}function _c(l,a,t,u){if(u={lane:2,revertLane:Qc(),action:u,hasEagerState:!1,eagerState:null,next:null},dn(l)){if(a)throw Error(o(479))}else a=vc(l,t,u,2),a!==null&&Hl(a,l,2)}function dn(l){var a=l.alternate;return l===H||a!==null&&a===H}function x1(l,a){Ot=Qe=!0;var t=l.pending;t===null?a.next=a:(a.next=t.next,t.next=a),l.pending=a}function j1(l,a,t){if(t&4194048){var u=a.lanes;u&=l.pendingLanes,t|=u,a.lanes=t,N0(l,t)}}var xe={readContext:sl,use:yn,useCallback:F,useContext:F,useEffect:F,useImperativeHandle:F,useLayoutEffect:F,useInsertionEffect:F,useMemo:F,useReducer:F,useRef:F,useState:F,useDebugValue:F,useDeferredValue:F,useTransition:F,useSyncExternalStore:F,useId:F,useHostTransitionStatus:F,useFormState:F,useActionState:F,useOptimistic:F,useMemoCache:F,useCacheRefresh:F},V1={readContext:sl,use:yn,useCallback:function(l,a){return Sl().memoizedState=[l,a===void 0?null:a],l},useContext:sl,useEffect:Ni,useImperativeHandle:function(l,a,t){t=t!=null?t.concat([l]):null,ze(4194308,4,H1.bind(null,a,l),t)},useLayoutEffect:function(l,a){return ze(4194308,4,l,a)},useInsertionEffect:function(l,a){ze(4,2,l,a)},useMemo:function(l,a){var t=Sl();a=a===void 0?null:a;var u=l();if(Ia){Ta(!0);try{l()}finally{Ta(!1)}}return t.memoizedState=[u,a],u},useReducer:function(l,a,t){var u=Sl();if(t!==void 0){var e=t(a);if(Ia){Ta(!0);try{t(a)}finally{Ta(!1)}}}else e=a;return u.memoizedState=u.baseState=e,l={pending:null,lanes:0,dispatch:null,lastRenderedReducer:l,lastRenderedState:e},u.queue=l,l=l.dispatch=Bh.bind(null,H,l),[u.memoizedState,l]},useRef:function(l){var a=Sl();return l={current:l},a.memoizedState=l},useState:function(l){l=Uf(l);var a=l.queue,t=Z1.bind(null,H,a);return a.dispatch=t,[l.memoizedState,t]},useDebugValue:Oc,useDeferredValue:function(l,a){var t=Sl();return Uc(t,l,a)},useTransition:function(){var l=Uf(!1);return l=B1.bind(null,H,l.queue,!0,!1),Sl().memoizedState=l,[!1,l]},useSyncExternalStore:function(l,a,t){var u=H,e=Sl();if(G){if(t===void 0)throw Error(o(407));t=t()}else{if(t=a(),C===null)throw Error(o(349));Y&124||s1(u,a,t)}e.memoizedState=t;var n={value:t,getSnapshot:a};return e.queue=n,Ni(S1.bind(null,u,n,l),[l]),u.flags|=2048,Xt(9,hn(),m1.bind(null,u,n,t,a),null),t},useId:function(){var l=Sl(),a=C.identifierPrefix;if(G){var t=ta,u=aa;t=(u&~(1<<32-Ol(u)-1)).toString(32)+t,a="«"+a+"R"+t,t=Ze++,0D?($=T,T=null):$=T.sibling;var B=d(y,T,s[D],g);if(B===null){T===null&&(T=$);break}l&&T&&B.alternate===null&&a(y,T),v=n(B,v,D),U===null?z=B:U.sibling=B,U=B,T=$}if(D===s.length)return t(y,T),G&&Ka(y,D),z;if(T===null){for(;DD?($=T,T=null):$=T.sibling;var Nl=d(y,T,B.value,g);if(Nl===null){T===null&&(T=$);break}l&&T&&Nl.alternate===null&&a(y,T),v=n(Nl,v,D),U===null?z=Nl:U.sibling=Nl,U=Nl,T=$}if(B.done)return t(y,T),G&&Ka(y,D),z;if(T===null){for(;!B.done;D++,B=s.next())B=S(y,B.value,g),B!==null&&(v=n(B,v,D),U===null?z=B:U.sibling=B,U=B);return G&&Ka(y,D),z}for(T=u(T);!B.done;D++,B=s.next())B=m(T,y,D,B.value,g),B!==null&&(l&&B.alternate!==null&&T.delete(B.key===null?D:B.key),v=n(B,v,D),U===null?z=B:U.sibling=B,U=B);return l&&T.forEach(function(da){return a(y,da)}),G&&Ka(y,D),z}function X(y,v,s,g){if(typeof s=="object"&&s!==null&&s.type===vt&&s.key===null&&(s=s.props.children),typeof s=="object"&&s!==null){switch(s.$$typeof){case Iu:l:{for(var z=s.key;v!==null;){if(v.key===z){if(z=s.type,z===vt){if(v.tag===7){t(y,v.sibling),g=e(v,s.props.children),g.return=y,y=g;break l}}else if(v.elementType===z||typeof z=="object"&&z!==null&&z.$$typeof===Sa&&qi(z)===v.type){t(y,v.sibling),g=e(v,s.props),kt(g,s),g.return=y,y=g;break l}t(y,v);break}else a(y,v);v=v.sibling}s.type===vt?(g=La(s.props.children,y.mode,g,s.key),g.return=y,y=g):(g=be(s.type,s.key,s.props,null,y.mode,g),kt(g,s),g.return=y,y=g)}return f(y);case lu:l:{for(z=s.key;v!==null;){if(v.key===z)if(v.tag===4&&v.stateNode.containerInfo===s.containerInfo&&v.stateNode.implementation===s.implementation){t(y,v.sibling),g=e(v,s.children||[]),g.return=y,y=g;break l}else{t(y,v);break}else a(y,v);v=v.sibling}g=Yn(s,y.mode,g),g.return=y,y=g}return f(y);case Sa:return z=s._init,s=z(s._payload),X(y,v,s,g)}if(au(s))return M(y,v,s,g);if(rt(s)){if(z=rt(s),typeof z!="function")throw Error(o(150));return s=z.call(s),E(y,v,s,g)}if(typeof s.then=="function")return X(y,v,ne(s),g);if(s.$$typeof===la)return X(y,v,ue(y,s),g);fe(y,s)}return typeof s=="string"&&s!==""||typeof s=="number"||typeof s=="bigint"?(s=""+s,v!==null&&v.tag===6?(t(y,v.sibling),g=e(v,s),g.return=y,y=g):(t(y,v),g=Bn(s,y.mode,g),g.return=y,y=g),f(y)):t(y,v)}return function(y,v,s,g){try{Du=0;var z=X(y,v,s,g);return Ht=null,z}catch(T){if(T===Ku||T===vn)throw T;var U=Ml(29,T,null,y.mode);return U.lanes=g,U.return=y,U}finally{}}}var Gt=C1(!0),p1=C1(!1),Zl=Wl(null),wl=null;function oa(l){var a=l.alternate;J(tl,tl.current&1),J(Zl,l),wl===null&&(a===null||Yt.current!==null||a.memoizedState!==null)&&(wl=l)}function L1(l){if(l.tag===22){if(J(tl,tl.current),J(Zl,l),wl===null){var a=l.alternate;a!==null&&a.memoizedState!==null&&(wl=l)}}else za()}function za(){J(tl,tl.current),J(Zl,Zl.current)}function ea(l){il(Zl),wl===l&&(wl=null),il(tl)}var tl=Wl(0);function je(l){for(var a=l;a!==null;){if(a.tag===13){var t=a.memoizedState;if(t!==null&&(t=t.dehydrated,t===null||t.data==="$?"||Jf(t)))return a}else if(a.tag===19&&a.memoizedProps.revealOrder!==void 0){if(a.flags&128)return a}else if(a.child!==null){a.child.return=a,a=a.child;continue}if(a===l)break;for(;a.sibling===null;){if(a.return===null||a.return===l)return null;a=a.return}a.sibling.return=a.return,a=a.sibling}return null}function Qn(l,a,t,u){a=l.memoizedState,t=t(u,a),t=t==null?a:p({},a,t),l.memoizedState=t,l.lanes===0&&(l.updateQueue.baseState=t)}var Nf={enqueueSetState:function(l,a,t){l=l._reactInternals;var u=Ul(),e=Ua(u);e.payload=a,t!=null&&(e.callback=t),a=Ha(l,e,u),a!==null&&(Hl(a,l,u),vu(a,l,u))},enqueueReplaceState:function(l,a,t){l=l._reactInternals;var u=Ul(),e=Ua(u);e.tag=1,e.payload=a,t!=null&&(e.callback=t),a=Ha(l,e,u),a!==null&&(Hl(a,l,u),vu(a,l,u))},enqueueForceUpdate:function(l,a){l=l._reactInternals;var t=Ul(),u=Ua(t);u.tag=2,a!=null&&(u.callback=a),a=Ha(l,u,t),a!==null&&(Hl(a,l,t),vu(a,l,t))}};function Ri(l,a,t,u,e,n,f){return l=l.stateNode,typeof l.shouldComponentUpdate=="function"?l.shouldComponentUpdate(u,n,f):a.prototype&&a.prototype.isPureReactComponent?!Tu(t,u)||!Tu(e,n):!0}function Bi(l,a,t,u){l=a.state,typeof a.componentWillReceiveProps=="function"&&a.componentWillReceiveProps(t,u),typeof a.UNSAFE_componentWillReceiveProps=="function"&&a.UNSAFE_componentWillReceiveProps(t,u),a.state!==l&&Nf.enqueueReplaceState(a,a.state,null)}function Pa(l,a){var t=a;if("ref"in a){t={};for(var u in a)u!=="ref"&&(t[u]=a[u])}if(l=l.defaultProps){t===a&&(t=p({},t));for(var e in l)t[e]===void 0&&(t[e]=l[e])}return t}var Ve=typeof reportError=="function"?reportError:function(l){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var a=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof l=="object"&&l!==null&&typeof l.message=="string"?String(l.message):String(l),error:l});if(!window.dispatchEvent(a))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",l);return}console.error(l)};function J1(l){Ve(l)}function r1(l){console.error(l)}function w1(l){Ve(l)}function Ke(l,a){try{var t=l.onUncaughtError;t(a.value,{componentStack:a.stack})}catch(u){setTimeout(function(){throw u})}}function Yi(l,a,t){try{var u=l.onCaughtError;u(t.value,{componentStack:t.stack,errorBoundary:a.tag===1?a.stateNode:null})}catch(e){setTimeout(function(){throw e})}}function qf(l,a,t){return t=Ua(t),t.tag=3,t.payload={element:null},t.callback=function(){Ke(l,a)},t}function W1(l){return l=Ua(l),l.tag=3,l}function $1(l,a,t,u){var e=t.type.getDerivedStateFromError;if(typeof e=="function"){var n=u.value;l.payload=function(){return e(n)},l.callback=function(){Yi(a,t,u)}}var f=t.stateNode;f!==null&&typeof f.componentDidCatch=="function"&&(l.callback=function(){Yi(a,t,u),typeof e!="function"&&(_a===null?_a=new Set([this]):_a.add(this));var c=u.stack;this.componentDidCatch(u.value,{componentStack:c!==null?c:""})})}function Xh(l,a,t,u,e){if(t.flags|=32768,u!==null&&typeof u=="object"&&typeof u.then=="function"){if(a=t.alternate,a!==null&&ju(a,t,e,!0),t=Zl.current,t!==null){switch(t.tag){case 13:return wl===null?xf():t.alternate===null&&W===0&&(W=3),t.flags&=-257,t.flags|=65536,t.lanes=e,u===Ef?t.flags|=16384:(a=t.updateQueue,a===null?t.updateQueue=new Set([u]):a.add(u),wn(l,u,e)),!1;case 22:return t.flags|=65536,u===Ef?t.flags|=16384:(a=t.updateQueue,a===null?(a={transitions:null,markerInstances:null,retryQueue:new Set([u])},t.updateQueue=a):(t=a.retryQueue,t===null?a.retryQueue=new Set([u]):t.add(u)),wn(l,u,e)),!1}throw Error(o(435,t.tag))}return wn(l,u,e),xf(),!1}if(G)return a=Zl.current,a!==null?(!(a.flags&65536)&&(a.flags|=256),a.flags|=65536,a.lanes=e,u!==gf&&(l=Error(o(422),{cause:u}),Eu(Gl(l,t)))):(u!==gf&&(a=Error(o(423),{cause:u}),Eu(Gl(a,t))),l=l.current.alternate,l.flags|=65536,e&=-e,l.lanes|=e,u=Gl(u,t),e=qf(l.stateNode,u,e),Xn(l,e),W!==4&&(W=2)),!1;var n=Error(o(520),{cause:u});if(n=Gl(n,t),Su===null?Su=[n]:Su.push(n),W!==4&&(W=2),a===null)return!0;u=Gl(u,t),t=a;do{switch(t.tag){case 3:return t.flags|=65536,l=e&-e,t.lanes|=l,l=qf(t.stateNode,u,l),Xn(t,l),!1;case 1:if(a=t.type,n=t.stateNode,(t.flags&128)===0&&(typeof a.getDerivedStateFromError=="function"||n!==null&&typeof n.componentDidCatch=="function"&&(_a===null||!_a.has(n))))return t.flags|=65536,e&=-e,t.lanes|=e,e=W1(e),$1(e,l,t,u),Xn(t,e),!1}t=t.return}while(t!==null);return!1}var k1=Error(o(461)),cl=!1;function vl(l,a,t,u){a.child=l===null?p1(a,null,t,u):Gt(a,l.child,t,u)}function Xi(l,a,t,u,e){t=t.render;var n=a.ref;if("ref"in u){var f={};for(var c in u)c!=="ref"&&(f[c]=u[c])}else f=u;return Fa(a),u=oc(l,a,t,f,n,e),c=zc(),l!==null&&!cl?(Ac(l,a,e),va(l,a,e)):(G&&c&&hc(a),a.flags|=1,vl(l,a,u,e),a.child)}function Gi(l,a,t,u,e){if(l===null){var n=t.type;return typeof n=="function"&&!yc(n)&&n.defaultProps===void 0&&t.compare===null?(a.tag=15,a.type=n,F1(l,a,n,u,e)):(l=be(t.type,null,u,a,a.mode,e),l.ref=a.ref,l.return=a,a.child=l)}if(n=l.child,!Nc(l,e)){var f=n.memoizedProps;if(t=t.compare,t=t!==null?t:Tu,t(f,u)&&l.ref===a.ref)return va(l,a,e)}return a.flags|=1,l=na(n,u),l.ref=a.ref,l.return=a,a.child=l}function F1(l,a,t,u,e){if(l!==null){var n=l.memoizedProps;if(Tu(n,u)&&l.ref===a.ref)if(cl=!1,a.pendingProps=u=n,Nc(l,e))l.flags&131072&&(cl=!0);else return a.lanes=l.lanes,va(l,a,e)}return Rf(l,a,t,u,e)}function I1(l,a,t){var u=a.pendingProps,e=u.children,n=l!==null?l.memoizedState:null;if(u.mode==="hidden"){if(a.flags&128){if(u=n!==null?n.baseLanes|t:t,l!==null){for(e=a.child=l.child,n=0;e!==null;)n=n|e.lanes|e.childLanes,e=e.sibling;a.childLanes=n&~u}else a.childLanes=0,a.child=null;return Qi(l,a,u,t)}if(t&536870912)a.memoizedState={baseLanes:0,cachePool:null},l!==null&&ge(a,n!==null?n.cachePool:null),n!==null?Mi(a,n):Of(),L1(a);else return a.lanes=a.childLanes=536870912,Qi(l,a,n!==null?n.baseLanes|t:t,t)}else n!==null?(ge(a,n.cachePool),Mi(a,n),za(),a.memoizedState=null):(l!==null&&ge(a,null),Of(),za());return vl(l,a,e,t),a.child}function Qi(l,a,t,u){var e=mc();return e=e===null?null:{parent:al._currentValue,pool:e},a.memoizedState={baseLanes:t,cachePool:e},l!==null&&ge(a,null),Of(),L1(a),l!==null&&ju(l,a,u,!0),null}function Ae(l,a){var t=a.ref;if(t===null)l!==null&&l.ref!==null&&(a.flags|=4194816);else{if(typeof t!="function"&&typeof t!="object")throw Error(o(284));(l===null||l.ref!==t)&&(a.flags|=4194816)}}function Rf(l,a,t,u,e){return Fa(a),t=oc(l,a,t,u,void 0,e),u=zc(),l!==null&&!cl?(Ac(l,a,e),va(l,a,e)):(G&&u&&hc(a),a.flags|=1,vl(l,a,t,e),a.child)}function Zi(l,a,t,u,e,n){return Fa(a),a.updateQueue=null,t=h1(a,u,t,e),y1(l),u=zc(),l!==null&&!cl?(Ac(l,a,n),va(l,a,n)):(G&&u&&hc(a),a.flags|=1,vl(l,a,t,n),a.child)}function xi(l,a,t,u,e){if(Fa(a),a.stateNode===null){var n=gt,f=t.contextType;typeof f=="object"&&f!==null&&(n=sl(f)),n=new t(u,n),a.memoizedState=n.state!==null&&n.state!==void 0?n.state:null,n.updater=Nf,a.stateNode=n,n._reactInternals=a,n=a.stateNode,n.props=u,n.state=a.memoizedState,n.refs={},Sc(a),f=t.contextType,n.context=typeof f=="object"&&f!==null?sl(f):gt,n.state=a.memoizedState,f=t.getDerivedStateFromProps,typeof f=="function"&&(Qn(a,t,f,u),n.state=a.memoizedState),typeof t.getDerivedStateFromProps=="function"||typeof n.getSnapshotBeforeUpdate=="function"||typeof n.UNSAFE_componentWillMount!="function"&&typeof n.componentWillMount!="function"||(f=n.state,typeof n.componentWillMount=="function"&&n.componentWillMount(),typeof n.UNSAFE_componentWillMount=="function"&&n.UNSAFE_componentWillMount(),f!==n.state&&Nf.enqueueReplaceState(n,n.state,null),hu(a,u,n,e),yu(),n.state=a.memoizedState),typeof n.componentDidMount=="function"&&(a.flags|=4194308),u=!0}else if(l===null){n=a.stateNode;var c=a.memoizedProps,i=Pa(t,c);n.props=i;var h=n.context,b=t.contextType;f=gt,typeof b=="object"&&b!==null&&(f=sl(b));var S=t.getDerivedStateFromProps;b=typeof S=="function"||typeof n.getSnapshotBeforeUpdate=="function",c=a.pendingProps!==c,b||typeof n.UNSAFE_componentWillReceiveProps!="function"&&typeof n.componentWillReceiveProps!="function"||(c||h!==f)&&Bi(a,n,u,f),ba=!1;var d=a.memoizedState;n.state=d,hu(a,u,n,e),yu(),h=a.memoizedState,c||d!==h||ba?(typeof S=="function"&&(Qn(a,t,S,u),h=a.memoizedState),(i=ba||Ri(a,t,i,u,d,h,f))?(b||typeof n.UNSAFE_componentWillMount!="function"&&typeof n.componentWillMount!="function"||(typeof n.componentWillMount=="function"&&n.componentWillMount(),typeof n.UNSAFE_componentWillMount=="function"&&n.UNSAFE_componentWillMount()),typeof n.componentDidMount=="function"&&(a.flags|=4194308)):(typeof n.componentDidMount=="function"&&(a.flags|=4194308),a.memoizedProps=u,a.memoizedState=h),n.props=u,n.state=h,n.context=f,u=i):(typeof n.componentDidMount=="function"&&(a.flags|=4194308),u=!1)}else{n=a.stateNode,Mf(l,a),f=a.memoizedProps,b=Pa(t,f),n.props=b,S=a.pendingProps,d=n.context,h=t.contextType,i=gt,typeof h=="object"&&h!==null&&(i=sl(h)),c=t.getDerivedStateFromProps,(h=typeof c=="function"||typeof n.getSnapshotBeforeUpdate=="function")||typeof n.UNSAFE_componentWillReceiveProps!="function"&&typeof n.componentWillReceiveProps!="function"||(f!==S||d!==i)&&Bi(a,n,u,i),ba=!1,d=a.memoizedState,n.state=d,hu(a,u,n,e),yu();var m=a.memoizedState;f!==S||d!==m||ba||l!==null&&l.dependencies!==null&&Xe(l.dependencies)?(typeof c=="function"&&(Qn(a,t,c,u),m=a.memoizedState),(b=ba||Ri(a,t,b,u,d,m,i)||l!==null&&l.dependencies!==null&&Xe(l.dependencies))?(h||typeof n.UNSAFE_componentWillUpdate!="function"&&typeof n.componentWillUpdate!="function"||(typeof n.componentWillUpdate=="function"&&n.componentWillUpdate(u,m,i),typeof n.UNSAFE_componentWillUpdate=="function"&&n.UNSAFE_componentWillUpdate(u,m,i)),typeof n.componentDidUpdate=="function"&&(a.flags|=4),typeof n.getSnapshotBeforeUpdate=="function"&&(a.flags|=1024)):(typeof n.componentDidUpdate!="function"||f===l.memoizedProps&&d===l.memoizedState||(a.flags|=4),typeof n.getSnapshotBeforeUpdate!="function"||f===l.memoizedProps&&d===l.memoizedState||(a.flags|=1024),a.memoizedProps=u,a.memoizedState=m),n.props=u,n.state=m,n.context=i,u=b):(typeof n.componentDidUpdate!="function"||f===l.memoizedProps&&d===l.memoizedState||(a.flags|=4),typeof n.getSnapshotBeforeUpdate!="function"||f===l.memoizedProps&&d===l.memoizedState||(a.flags|=1024),u=!1)}return n=u,Ae(l,a),u=(a.flags&128)!==0,n||u?(n=a.stateNode,t=u&&typeof t.getDerivedStateFromError!="function"?null:n.render(),a.flags|=1,l!==null&&u?(a.child=Gt(a,l.child,null,e),a.child=Gt(a,null,t,e)):vl(l,a,t,e),a.memoizedState=n.state,l=a.child):l=va(l,a,e),l}function ji(l,a,t,u){return xu(),a.flags|=256,vl(l,a,t,u),a.child}var Zn={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function xn(l){return{baseLanes:l,cachePool:n1()}}function jn(l,a,t){return l=l!==null?l.childLanes&~t:0,a&&(l|=Ql),l}function P1(l,a,t){var u=a.pendingProps,e=!1,n=(a.flags&128)!==0,f;if((f=n)||(f=l!==null&&l.memoizedState===null?!1:(tl.current&2)!==0),f&&(e=!0,a.flags&=-129),f=(a.flags&32)!==0,a.flags&=-33,l===null){if(G){if(e?oa(a):za(),G){var c=w,i;if(i=c){l:{for(i=c,c=pl;i.nodeType!==8;){if(!c){c=null;break l}if(i=Vl(i.nextSibling),i===null){c=null;break l}}c=i}c!==null?(a.memoizedState={dehydrated:c,treeContext:Ja!==null?{id:aa,overflow:ta}:null,retryLane:536870912,hydrationErrors:null},i=Ml(18,null,null,0),i.stateNode=c,i.return=a,a.child=i,ml=a,w=null,i=!0):i=!1}i||ka(a)}if(c=a.memoizedState,c!==null&&(c=c.dehydrated,c!==null))return Jf(c)?a.lanes=32:a.lanes=536870912,null;ea(a)}return c=u.children,u=u.fallback,e?(za(),e=a.mode,c=Ce({mode:"hidden",children:c},e),u=La(u,e,t,null),c.return=a,u.return=a,c.sibling=u,a.child=c,e=a.child,e.memoizedState=xn(t),e.childLanes=jn(l,f,t),a.memoizedState=Zn,u):(oa(a),Bf(a,c))}if(i=l.memoizedState,i!==null&&(c=i.dehydrated,c!==null)){if(n)a.flags&256?(oa(a),a.flags&=-257,a=Vn(l,a,t)):a.memoizedState!==null?(za(),a.child=l.child,a.flags|=128,a=null):(za(),e=u.fallback,c=a.mode,u=Ce({mode:"visible",children:u.children},c),e=La(e,c,t,null),e.flags|=2,u.return=a,e.return=a,u.sibling=e,a.child=u,Gt(a,l.child,null,t),u=a.child,u.memoizedState=xn(t),u.childLanes=jn(l,f,t),a.memoizedState=Zn,a=e);else if(oa(a),Jf(c)){if(f=c.nextSibling&&c.nextSibling.dataset,f)var h=f.dgst;f=h,u=Error(o(419)),u.stack="",u.digest=f,Eu({value:u,source:null,stack:null}),a=Vn(l,a,t)}else if(cl||ju(l,a,t,!1),f=(t&l.childLanes)!==0,cl||f){if(f=C,f!==null&&(u=t&-t,u=u&42?1:Pf(u),u=u&(f.suspendedLanes|t)?0:u,u!==0&&u!==i.retryLane))throw i.retryLane=u,Ct(l,u),Hl(f,l,u),k1;c.data==="$?"||xf(),a=Vn(l,a,t)}else c.data==="$?"?(a.flags|=192,a.child=l.child,a=null):(l=i.treeContext,w=Vl(c.nextSibling),ml=a,G=!0,ra=null,pl=!1,l!==null&&(Bl[Yl++]=aa,Bl[Yl++]=ta,Bl[Yl++]=Ja,aa=l.id,ta=l.overflow,Ja=a),a=Bf(a,u.children),a.flags|=4096);return a}return e?(za(),e=u.fallback,c=a.mode,i=l.child,h=i.sibling,u=na(i,{mode:"hidden",children:u.children}),u.subtreeFlags=i.subtreeFlags&65011712,h!==null?e=na(h,e):(e=La(e,c,t,null),e.flags|=2),e.return=a,u.return=a,u.sibling=e,a.child=u,u=e,e=a.child,c=l.child.memoizedState,c===null?c=xn(t):(i=c.cachePool,i!==null?(h=al._currentValue,i=i.parent!==h?{parent:h,pool:h}:i):i=n1(),c={baseLanes:c.baseLanes|t,cachePool:i}),e.memoizedState=c,e.childLanes=jn(l,f,t),a.memoizedState=Zn,u):(oa(a),t=l.child,l=t.sibling,t=na(t,{mode:"visible",children:u.children}),t.return=a,t.sibling=null,l!==null&&(f=a.deletions,f===null?(a.deletions=[l],a.flags|=16):f.push(l)),a.child=t,a.memoizedState=null,t)}function Bf(l,a){return a=Ce({mode:"visible",children:a},l.mode),a.return=l,l.child=a}function Ce(l,a){return l=Ml(22,l,null,a),l.lanes=0,l.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},l}function Vn(l,a,t){return Gt(a,l.child,null,t),l=Bf(a,a.pendingProps.children),l.flags|=2,a.memoizedState=null,l}function Vi(l,a,t){l.lanes|=a;var u=l.alternate;u!==null&&(u.lanes|=a),zf(l.return,a,t)}function Kn(l,a,t,u,e){var n=l.memoizedState;n===null?l.memoizedState={isBackwards:a,rendering:null,renderingStartTime:0,last:u,tail:t,tailMode:e}:(n.isBackwards=a,n.rendering=null,n.renderingStartTime=0,n.last=u,n.tail=t,n.tailMode=e)}function lv(l,a,t){var u=a.pendingProps,e=u.revealOrder,n=u.tail;if(vl(l,a,u.children,t),u=tl.current,u&2)u=u&1|2,a.flags|=128;else{if(l!==null&&l.flags&128)l:for(l=a.child;l!==null;){if(l.tag===13)l.memoizedState!==null&&Vi(l,t,a);else if(l.tag===19)Vi(l,t,a);else if(l.child!==null){l.child.return=l,l=l.child;continue}if(l===a)break l;for(;l.sibling===null;){if(l.return===null||l.return===a)break l;l=l.return}l.sibling.return=l.return,l=l.sibling}u&=1}switch(J(tl,u),e){case"forwards":for(t=a.child,e=null;t!==null;)l=t.alternate,l!==null&&je(l)===null&&(e=t),t=t.sibling;t=e,t===null?(e=a.child,a.child=null):(e=t.sibling,t.sibling=null),Kn(a,!1,e,t,n);break;case"backwards":for(t=null,e=a.child,a.child=null;e!==null;){if(l=e.alternate,l!==null&&je(l)===null){a.child=e;break}l=e.sibling,e.sibling=t,t=e,e=l}Kn(a,!0,t,null,n);break;case"together":Kn(a,!1,null,null,void 0);break;default:a.memoizedState=null}return a.child}function va(l,a,t){if(l!==null&&(a.dependencies=l.dependencies),Ga|=a.lanes,!(t&a.childLanes))if(l!==null){if(ju(l,a,t,!1),(t&a.childLanes)===0)return null}else return null;if(l!==null&&a.child!==l.child)throw Error(o(153));if(a.child!==null){for(l=a.child,t=na(l,l.pendingProps),a.child=t,t.return=a;l.sibling!==null;)l=l.sibling,t=t.sibling=na(l,l.pendingProps),t.return=a;t.sibling=null}return a.child}function Nc(l,a){return l.lanes&a?!0:(l=l.dependencies,!!(l!==null&&Xe(l)))}function Gh(l,a,t){switch(a.tag){case 3:Ue(a,a.stateNode.containerInfo),ga(a,al,l.memoizedState.cache),xu();break;case 27:case 5:ff(a);break;case 4:Ue(a,a.stateNode.containerInfo);break;case 10:ga(a,a.type,a.memoizedProps.value);break;case 13:var u=a.memoizedState;if(u!==null)return u.dehydrated!==null?(oa(a),a.flags|=128,null):t&a.child.childLanes?P1(l,a,t):(oa(a),l=va(l,a,t),l!==null?l.sibling:null);oa(a);break;case 19:var e=(l.flags&128)!==0;if(u=(t&a.childLanes)!==0,u||(ju(l,a,t,!1),u=(t&a.childLanes)!==0),e){if(u)return lv(l,a,t);a.flags|=128}if(e=a.memoizedState,e!==null&&(e.rendering=null,e.tail=null,e.lastEffect=null),J(tl,tl.current),u)break;return null;case 22:case 23:return a.lanes=0,I1(l,a,t);case 24:ga(a,al,l.memoizedState.cache)}return va(l,a,t)}function av(l,a,t){if(l!==null)if(l.memoizedProps!==a.pendingProps)cl=!0;else{if(!Nc(l,t)&&!(a.flags&128))return cl=!1,Gh(l,a,t);cl=!!(l.flags&131072)}else cl=!1,G&&a.flags&1048576&&u1(a,Ye,a.index);switch(a.lanes=0,a.tag){case 16:l:{l=a.pendingProps;var u=a.elementType,e=u._init;if(u=e(u._payload),a.type=u,typeof u=="function")yc(u)?(l=Pa(u,l),a.tag=1,a=xi(null,a,u,l,t)):(a.tag=0,a=Rf(null,a,u,l,t));else{if(u!=null){if(e=u.$$typeof,e===kf){a.tag=11,a=Xi(null,a,u,l,t);break l}else if(e===Ff){a.tag=14,a=Gi(null,a,u,l,t);break l}}throw a=ef(u)||u,Error(o(306,a,""))}}return a;case 0:return Rf(l,a,a.type,a.pendingProps,t);case 1:return u=a.type,e=Pa(u,a.pendingProps),xi(l,a,u,e,t);case 3:l:{if(Ue(a,a.stateNode.containerInfo),l===null)throw Error(o(387));u=a.pendingProps;var n=a.memoizedState;e=n.element,Mf(l,a),hu(a,u,null,t);var f=a.memoizedState;if(u=f.cache,ga(a,al,u),u!==n.cache&&Af(a,[al],t,!0),yu(),u=f.element,n.isDehydrated)if(n={element:u,isDehydrated:!1,cache:f.cache},a.updateQueue.baseState=n,a.memoizedState=n,a.flags&256){a=ji(l,a,u,t);break l}else if(u!==e){e=Gl(Error(o(424)),a),Eu(e),a=ji(l,a,u,t);break l}else{switch(l=a.stateNode.containerInfo,l.nodeType){case 9:l=l.body;break;default:l=l.nodeName==="HTML"?l.ownerDocument.body:l}for(w=Vl(l.firstChild),ml=a,G=!0,ra=null,pl=!0,t=p1(a,null,u,t),a.child=t;t;)t.flags=t.flags&-3|4096,t=t.sibling}else{if(xu(),u===e){a=va(l,a,t);break l}vl(l,a,u,t)}a=a.child}return a;case 26:return Ae(l,a),l===null?(t=u0(a.type,null,a.pendingProps,null))?a.memoizedState=t:G||(t=a.type,l=a.pendingProps,u=$e(Oa.current).createElement(t),u[dl]=a,u[ol]=l,hl(u,t,l),fl(u),a.stateNode=u):a.memoizedState=u0(a.type,l.memoizedProps,a.pendingProps,l.memoizedState),null;case 27:return ff(a),l===null&&G&&(u=a.stateNode=Kv(a.type,a.pendingProps,Oa.current),ml=a,pl=!0,e=w,Za(a.type)?(rf=e,w=Vl(u.firstChild)):w=e),vl(l,a,a.pendingProps.children,t),Ae(l,a),l===null&&(a.flags|=4194304),a.child;case 5:return l===null&&G&&((e=u=w)&&(u=vd(u,a.type,a.pendingProps,pl),u!==null?(a.stateNode=u,ml=a,w=Vl(u.firstChild),pl=!1,e=!0):e=!1),e||ka(a)),ff(a),e=a.type,n=a.pendingProps,f=l!==null?l.memoizedProps:null,u=n.children,pf(e,n)?u=null:f!==null&&pf(e,f)&&(a.flags|=32),a.memoizedState!==null&&(e=oc(l,a,Hh,null,null,t),_u._currentValue=e),Ae(l,a),vl(l,a,u,t),a.child;case 6:return l===null&&G&&((l=t=w)&&(t=yd(t,a.pendingProps,pl),t!==null?(a.stateNode=t,ml=a,w=null,l=!0):l=!1),l||ka(a)),null;case 13:return P1(l,a,t);case 4:return Ue(a,a.stateNode.containerInfo),u=a.pendingProps,l===null?a.child=Gt(a,null,u,t):vl(l,a,u,t),a.child;case 11:return Xi(l,a,a.type,a.pendingProps,t);case 7:return vl(l,a,a.pendingProps,t),a.child;case 8:return vl(l,a,a.pendingProps.children,t),a.child;case 12:return vl(l,a,a.pendingProps.children,t),a.child;case 10:return u=a.pendingProps,ga(a,a.type,u.value),vl(l,a,u.children,t),a.child;case 9:return e=a.type._context,u=a.pendingProps.children,Fa(a),e=sl(e),u=u(e),a.flags|=1,vl(l,a,u,t),a.child;case 14:return Gi(l,a,a.type,a.pendingProps,t);case 15:return F1(l,a,a.type,a.pendingProps,t);case 19:return lv(l,a,t);case 31:return u=a.pendingProps,t=a.mode,u={mode:u.mode,children:u.children},l===null?(t=Ce(u,t),t.ref=a.ref,a.child=t,t.return=a,a=t):(t=na(l.child,u),t.ref=a.ref,a.child=t,t.return=a,a=t),a;case 22:return I1(l,a,t);case 24:return Fa(a),u=sl(al),l===null?(e=mc(),e===null&&(e=C,n=sc(),e.pooledCache=n,n.refCount++,n!==null&&(e.pooledCacheLanes|=t),e=n),a.memoizedState={parent:u,cache:e},Sc(a),ga(a,al,e)):(l.lanes&t&&(Mf(l,a),hu(a,null,null,t),yu()),e=l.memoizedState,n=a.memoizedState,e.parent!==u?(e={parent:u,cache:u},a.memoizedState=e,a.lanes===0&&(a.memoizedState=a.updateQueue.baseState=e),ga(a,al,u)):(u=n.cache,ga(a,al,u),u!==e.cache&&Af(a,[al],t,!0))),vl(l,a,a.pendingProps.children,t),a.child;case 29:throw a.pendingProps}throw Error(o(156,a.tag))}function Fl(l){l.flags|=4}function Ki(l,a){if(a.type!=="stylesheet"||a.state.loading&4)l.flags&=-16777217;else if(l.flags|=16777216,!Lv(a)){if(a=Zl.current,a!==null&&((Y&4194048)===Y?wl!==null:(Y&62914560)!==Y&&!(Y&536870912)||a!==wl))throw iu=Ef,f1;l.flags|=8192}}function ce(l,a){a!==null&&(l.flags|=4),l.flags&16384&&(a=l.tag!==22?H0():536870912,l.lanes|=a,Qt|=a)}function Ft(l,a){if(!G)switch(l.tailMode){case"hidden":a=l.tail;for(var t=null;a!==null;)a.alternate!==null&&(t=a),a=a.sibling;t===null?l.tail=null:t.sibling=null;break;case"collapsed":t=l.tail;for(var u=null;t!==null;)t.alternate!==null&&(u=t),t=t.sibling;u===null?a||l.tail===null?l.tail=null:l.tail.sibling=null:u.sibling=null}}function r(l){var a=l.alternate!==null&&l.alternate.child===l.child,t=0,u=0;if(a)for(var e=l.child;e!==null;)t|=e.lanes|e.childLanes,u|=e.subtreeFlags&65011712,u|=e.flags&65011712,e.return=l,e=e.sibling;else for(e=l.child;e!==null;)t|=e.lanes|e.childLanes,u|=e.subtreeFlags,u|=e.flags,e.return=l,e=e.sibling;return l.subtreeFlags|=u,l.childLanes=t,a}function Qh(l,a,t){var u=a.pendingProps;switch(dc(a),a.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return r(a),null;case 1:return r(a),null;case 3:return t=a.stateNode,u=null,l!==null&&(u=l.memoizedState.cache),a.memoizedState.cache!==u&&(a.flags|=2048),fa(al),Nt(),t.pendingContext&&(t.context=t.pendingContext,t.pendingContext=null),(l===null||l.child===null)&&($t(a)?Fl(a):l===null||l.memoizedState.isDehydrated&&!(a.flags&256)||(a.flags|=1024,gi())),r(a),null;case 26:return t=a.memoizedState,l===null?(Fl(a),t!==null?(r(a),Ki(a,t)):(r(a),a.flags&=-16777217)):t?t!==l.memoizedState?(Fl(a),r(a),Ki(a,t)):(r(a),a.flags&=-16777217):(l.memoizedProps!==u&&Fl(a),r(a),a.flags&=-16777217),null;case 27:He(a),t=Oa.current;var e=a.type;if(l!==null&&a.stateNode!=null)l.memoizedProps!==u&&Fl(a);else{if(!u){if(a.stateNode===null)throw Error(o(166));return r(a),null}l=Jl.current,$t(a)?Si(a):(l=Kv(e,u,t),a.stateNode=l,Fl(a))}return r(a),null;case 5:if(He(a),t=a.type,l!==null&&a.stateNode!=null)l.memoizedProps!==u&&Fl(a);else{if(!u){if(a.stateNode===null)throw Error(o(166));return r(a),null}if(l=Jl.current,$t(a))Si(a);else{switch(e=$e(Oa.current),l){case 1:l=e.createElementNS("http://www.w3.org/2000/svg",t);break;case 2:l=e.createElementNS("http://www.w3.org/1998/Math/MathML",t);break;default:switch(t){case"svg":l=e.createElementNS("http://www.w3.org/2000/svg",t);break;case"math":l=e.createElementNS("http://www.w3.org/1998/Math/MathML",t);break;case"script":l=e.createElement("div"),l.innerHTML="