-
Notifications
You must be signed in to change notification settings - Fork 12
feat: 允许上传文件作为待匹配图片 #145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 允许上传文件作为待匹配图片 #145
Conversation
Reviewer's Guide添加对使用已上传图像作为自定义控制器源的支持,通过 MaaFW 和 Web UI 进行串联,并在使用该自定义控制器时禁用具有副作用的动作和点击。 上传图像并连接自定义控制器的时序图sequenceDiagram
actor User
participant WebUI as WebUI_master_control
participant MaaFW
participant MyCustomController
participant Tasker
participant AgentClient
User->>WebUI: Select Custom tab
User->>WebUI: Upload image file
WebUI->>WebUI: on_upload(e)
WebUI->>MaaFW: connect_custom_controller(e.content.read())
activate MaaFW
MaaFW->>MyCustomController: new(img_bytes)
activate MyCustomController
MyCustomController-->>MaaFW: instance with ndarray
MaaFW->>MyCustomController: post_connection()
MyCustomController-->>MaaFW: Future(wait).succeeded
deactivate MyCustomController
MaaFW-->>WebUI: True, None
deactivate MaaFW
WebUI-->>User: Show controller connected status
User->>WebUI: Start task
WebUI->>MaaFW: run_task(entry, pipeline_override)
activate MaaFW
MaaFW->>MaaFW: isinstance(controller, CustomController)
MaaFW->>MaaFW: pipeline_override.update(entry -> DoNothing)
MaaFW->>AgentClient: register_sink(resource, controller, tasker)
AgentClient-->>MaaFW: bool
MaaFW->>Tasker: post_task(entry, pipeline_override)
Tasker-->>MaaFW: Future(wait).succeeded
MaaFW-->>WebUI: succeeded, None
deactivate MaaFW
WebUI-->>User: Show task result without actions
带有 MyCustomController 和自定义控制器串联的 MaaFW 类图classDiagram
class CustomController {
<<abstract>>
+post_connection() Future
+post_click(x, y) Future
+screencap() ndarray
+connect() bool
+request_uuid() str
}
class MyCustomController {
+MyCustomController(img_bytes)
+ndarray ndarray
+connect() bool
+request_uuid() str
+screencap() ndarray
}
class AdbController {
+post_connection() Future
+post_click(x, y) Future
+screencap() ndarray
+connect() bool
+request_uuid() str
}
class Win32Controller {
+post_connection() Future
+post_click(x, y) Future
+screencap() ndarray
+connect() bool
+request_uuid() str
}
class Resource
class Tasker {
+post_task(entry, pipeline_override) Future
+stop() void
}
class AgentClient {
+register_sink(resource, controller, tasker) bool
}
class MaaFW {
+resource Resource
+controller AdbController
+controller Win32Controller
+controller CustomController
+tasker Tasker
+agent AgentClient
+connect_custom_controller(img_bytes) Tuple~bool, str~
+run_task(entry, pipeline_override) Tuple~bool, str~
+click(x, y) bool
}
CustomController <|-- MyCustomController
CustomController <|-- AdbController
CustomController <|-- Win32Controller
MaaFW --> Resource
MaaFW --> CustomController
MaaFW --> Tasker
MaaFW --> AgentClient
文件级变更
可能关联的问题
提示与命令与 Sourcery 交互
自定义你的体验访问你的 dashboard 来:
获取帮助Original review guide in EnglishReviewer's GuideAdds support for using an uploaded image as a custom controller source, wiring it through MaaFW and the web UI, and disables side-effectful actions and clicks when operating with this custom controller. Sequence diagram for uploading an image and connecting the custom controllersequenceDiagram
actor User
participant WebUI as WebUI_master_control
participant MaaFW
participant MyCustomController
participant Tasker
participant AgentClient
User->>WebUI: Select Custom tab
User->>WebUI: Upload image file
WebUI->>WebUI: on_upload(e)
WebUI->>MaaFW: connect_custom_controller(e.content.read())
activate MaaFW
MaaFW->>MyCustomController: new(img_bytes)
activate MyCustomController
MyCustomController-->>MaaFW: instance with ndarray
MaaFW->>MyCustomController: post_connection()
MyCustomController-->>MaaFW: Future(wait).succeeded
deactivate MyCustomController
MaaFW-->>WebUI: True, None
deactivate MaaFW
WebUI-->>User: Show controller connected status
User->>WebUI: Start task
WebUI->>MaaFW: run_task(entry, pipeline_override)
activate MaaFW
MaaFW->>MaaFW: isinstance(controller, CustomController)
MaaFW->>MaaFW: pipeline_override.update(entry -> DoNothing)
MaaFW->>AgentClient: register_sink(resource, controller, tasker)
AgentClient-->>MaaFW: bool
MaaFW->>Tasker: post_task(entry, pipeline_override)
Tasker-->>MaaFW: Future(wait).succeeded
MaaFW-->>WebUI: succeeded, None
deactivate MaaFW
WebUI-->>User: Show task result without actions
Class diagram for MaaFW with MyCustomController and custom controller wiringclassDiagram
class CustomController {
<<abstract>>
+post_connection() Future
+post_click(x, y) Future
+screencap() ndarray
+connect() bool
+request_uuid() str
}
class MyCustomController {
+MyCustomController(img_bytes)
+ndarray ndarray
+connect() bool
+request_uuid() str
+screencap() ndarray
}
class AdbController {
+post_connection() Future
+post_click(x, y) Future
+screencap() ndarray
+connect() bool
+request_uuid() str
}
class Win32Controller {
+post_connection() Future
+post_click(x, y) Future
+screencap() ndarray
+connect() bool
+request_uuid() str
}
class Resource
class Tasker {
+post_task(entry, pipeline_override) Future
+stop() void
}
class AgentClient {
+register_sink(resource, controller, tasker) bool
}
class MaaFW {
+resource Resource
+controller AdbController
+controller Win32Controller
+controller CustomController
+tasker Tasker
+agent AgentClient
+connect_custom_controller(img_bytes) Tuple~bool, str~
+run_task(entry, pipeline_override) Tuple~bool, str~
+click(x, y) bool
}
CustomController <|-- MyCustomController
CustomController <|-- AdbController
CustomController <|-- Win32Controller
MaaFW --> Resource
MaaFW --> CustomController
MaaFW --> Tasker
MaaFW --> AgentClient
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好——我已经审阅了你的修改,发现了一些需要处理的问题。
- 在
run_task中,pipeline_override.update(...)这行假设pipeline_override一定是一个字典;如果它可能为None或在调用方被省略,建议把它默认成{},或者在调用update前做判断,以避免出现AttributeError。 run_task里的两个分支都用完全相同的参数调用了self.tasker.post_task(...).wait().succeeded;你可以先计算好被覆盖后的 pipeline,只调用一次,以减少重复代码。- 在
connect_custom_control中,maafw.connect_custom_controller外层使用了裸except,会吞掉所有错误(包括编程错误);建议只捕获预期的异常类型,并考虑记录错误详情,以便调试。
给 AI 代理的提示词
请根据这次代码审查中的评论进行修改:
## 总体评论
- 在 `run_task` 中,`pipeline_override.update(...)` 这行假设 `pipeline_override` 一定是一个字典;如果它可能为 `None` 或在调用方被省略,建议把它默认成 `{}`,或者在调用 `update` 前做判断,以避免出现 `AttributeError`。
- `run_task` 里的两个分支都用完全相同的参数调用了 `self.tasker.post_task(...).wait().succeeded`;你可以先计算好被覆盖后的 pipeline,只调用一次,以减少重复代码。
- 在 `connect_custom_control` 中,`maafw.connect_custom_controller` 外层使用了裸 `except`,会吞掉所有错误(包括编程错误);建议只捕获预期的异常类型,并考虑记录错误详情,以便调试。
## 单独评论
### 评论 1
<location> `src/MaaDebugger/maafw/__init__.py:179-180` </location>
<code_context>
- return self.tasker.post_task(entry, pipeline_override).wait().succeeded, None
+ if isinstance(self.controller, CustomController):
+ # disable action
+ pipeline_override.update(
+ {entry: {"action": {"type": "DoNothing"}, "next": []}}
+ )
+ return (
</code_context>
<issue_to_address>
**issue:** 在调用 `update` 之前处理 `pipeline_override` 为 `None` 的情况。
在现有流程中,`pipeline_override` 可能为 `None`(之前是直接传给 `post_task` 的),但这个新分支假定它是字典,并对其调用 `update`,如果 `pipeline_override` 为 `None` 就会触发 `AttributeError`。建议在其为 `None` 时统一转换为一个空字典(例如 `pipeline_override = pipeline_override or {}`),或者让这个分支只在提供了字典时才执行。
</issue_to_address>
### 评论 2
<location> `src/MaaDebugger/maafw/__init__.py:111-115` </location>
<code_context>
return True, None
+ def connect_custom_controller(self, img_bytes) -> Tuple[bool, Optional[str]]:
+ self.controller = MyCustomController(img_bytes)
+ self.controller.post_connection().wait()
+
+ return True, None
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 检查 `post_connection()` 的结果,以与其他连接方法保持一致。
`connect_adb` 和 `connect_win32hwnd` 都会检查 `post_connection().wait().succeeded`,并在失败时返回 `(False, msg)`,但这个方法忽略了结果,总是返回 `(True, None)`。为了一致性及准确的错误报告,请在这里检查 `.succeeded`(以及可选的 `.message`),并在连接失败时返回失败的元组。
```suggestion
def connect_custom_controller(self, img_bytes) -> Tuple[bool, Optional[str]]:
self.controller = MyCustomController(img_bytes)
result = self.controller.post_connection().wait()
if not result.succeeded:
# 在失败时重置 controller,以保持与其他连接方法一致的状态
self.controller = None
return False, getattr(result, "message", None)
return True, None
```
</issue_to_address>
### 评论 3
<location> `src/MaaDebugger/webpage/index_page/master_control.py:310-316` </location>
<code_context>
+def connect_custom_control():
+ def on_upload(e):
+ GlobalStatus.ctrl_connecting = Status.RUNNING
+ try:
+ maafw.connect_custom_controller(e.content.read())
+ except:
+ GlobalStatus.ctrl_connecting = Status.FAILED
+ ui.notify("Failed to load image.", position="bottom-right", type="negative")
+ return
+
</code_context>
<issue_to_address>
**issue (bug_risk):** 处理上传错误时,避免使用裸 `except`。
裸 `except` 会隐藏所有错误,包括像 `TypeError` / `AttributeError` 这样的编程错误,并只显示一条通用提示。请只捕获你预期的上传/解码/连接相关异常,并考虑记录完整的异常信息,这样 `on_upload` 中的意外问题就不会被悄悄吞掉。
</issue_to_address>
### 评论 4
<location> `src/MaaDebugger/webpage/index_page/master_control.py:314` </location>
<code_context>
def connect_custom_control():
def on_upload(e):
GlobalStatus.ctrl_connecting = Status.RUNNING
try:
maafw.connect_custom_controller(e.content.read())
except:
GlobalStatus.ctrl_connecting = Status.FAILED
ui.notify("Failed to load image.", position="bottom-right", type="negative")
return
GlobalStatus.ctrl_connecting = Status.SUCCEEDED
StatusIndicator(GlobalStatus, "ctrl_connecting")
ui.upload(auto_upload=True, on_upload=lambda e: on_upload(e))
</code_context>
<issue_to_address>
**suggestion (code-quality):** 使用 `except Exception:` 替代裸 `except:`([`do-not-use-bare-except`](https://docs.sourcery.ai/Reference/Default-Rules/suggestions/do-not-use-bare-except/))
```suggestion
except Exception:
```
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的审查。
Original comment in English
Hey there - I've reviewed your changes and found some issues that need to be addressed.
- In
run_task, thepipeline_override.update(...)call assumespipeline_overrideis a dict; if it can beNoneor omitted by callers, consider defaulting it to{}or guarding the update to avoid anAttributeError. - The two branches in
run_taskboth callself.tasker.post_task(...).wait().succeededwith identical arguments; you can reduce duplication by computing the overridden pipeline once and then making a single call. - In
connect_custom_control, the bareexceptaroundmaafw.connect_custom_controllerwill swallow all errors (including programming errors); consider catching only the expected exceptions and optionally logging the error details to aid debugging.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `run_task`, the `pipeline_override.update(...)` call assumes `pipeline_override` is a dict; if it can be `None` or omitted by callers, consider defaulting it to `{}` or guarding the update to avoid an `AttributeError`.
- The two branches in `run_task` both call `self.tasker.post_task(...).wait().succeeded` with identical arguments; you can reduce duplication by computing the overridden pipeline once and then making a single call.
- In `connect_custom_control`, the bare `except` around `maafw.connect_custom_controller` will swallow all errors (including programming errors); consider catching only the expected exceptions and optionally logging the error details to aid debugging.
## Individual Comments
### Comment 1
<location> `src/MaaDebugger/maafw/__init__.py:179-180` </location>
<code_context>
- return self.tasker.post_task(entry, pipeline_override).wait().succeeded, None
+ if isinstance(self.controller, CustomController):
+ # disable action
+ pipeline_override.update(
+ {entry: {"action": {"type": "DoNothing"}, "next": []}}
+ )
+ return (
</code_context>
<issue_to_address>
**issue:** Handle the case where `pipeline_override` is `None` before calling `update`.
In the existing flow `pipeline_override` can be `None` (it was passed directly to `post_task`), but this new branch assumes it’s a dict and calls `update`, which will raise `AttributeError` when `pipeline_override` is `None`. Consider normalizing to an empty dict when it’s `None` (e.g. `pipeline_override = pipeline_override or {}`) or guarding this branch so it only runs when a dict is provided.
</issue_to_address>
### Comment 2
<location> `src/MaaDebugger/maafw/__init__.py:111-115` </location>
<code_context>
return True, None
+ def connect_custom_controller(self, img_bytes) -> Tuple[bool, Optional[str]]:
+ self.controller = MyCustomController(img_bytes)
+ self.controller.post_connection().wait()
+
+ return True, None
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Check the result of `post_connection()` to align with other connect methods.
`connect_adb` and `connect_win32hwnd` both check `post_connection().wait().succeeded` and return `(False, msg)` on failure, but this method ignores the result and always returns `(True, None)`. For consistency and accurate error reporting, please check `.succeeded` (and optionally `.message`) here and return a failure tuple when the connection fails.
```suggestion
def connect_custom_controller(self, img_bytes) -> Tuple[bool, Optional[str]]:
self.controller = MyCustomController(img_bytes)
result = self.controller.post_connection().wait()
if not result.succeeded:
# Reset controller on failure to keep state consistent with other connect methods
self.controller = None
return False, getattr(result, "message", None)
return True, None
```
</issue_to_address>
### Comment 3
<location> `src/MaaDebugger/webpage/index_page/master_control.py:310-316` </location>
<code_context>
+def connect_custom_control():
+ def on_upload(e):
+ GlobalStatus.ctrl_connecting = Status.RUNNING
+ try:
+ maafw.connect_custom_controller(e.content.read())
+ except:
+ GlobalStatus.ctrl_connecting = Status.FAILED
+ ui.notify("Failed to load image.", position="bottom-right", type="negative")
+ return
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid a bare `except` when handling upload errors.
A bare `except` will hide all errors, including programmer mistakes like `TypeError`/`AttributeError`, and only show a generic notification. Please catch only the specific upload/decoding/connection exceptions you expect, and consider logging the full exception so unexpected issues in `on_upload` aren’t silently masked.
</issue_to_address>
### Comment 4
<location> `src/MaaDebugger/webpage/index_page/master_control.py:314` </location>
<code_context>
def connect_custom_control():
def on_upload(e):
GlobalStatus.ctrl_connecting = Status.RUNNING
try:
maafw.connect_custom_controller(e.content.read())
except:
GlobalStatus.ctrl_connecting = Status.FAILED
ui.notify("Failed to load image.", position="bottom-right", type="negative")
return
GlobalStatus.ctrl_connecting = Status.SUCCEEDED
StatusIndicator(GlobalStatus, "ctrl_connecting")
ui.upload(auto_upload=True, on_upload=lambda e: on_upload(e))
</code_context>
<issue_to_address>
**suggestion (code-quality):** Use `except Exception:` rather than bare `except:` ([`do-not-use-bare-except`](https://docs.sourcery.ai/Reference/Default-Rules/suggestions/do-not-use-bare-except/))
```suggestion
except Exception:
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for uploading custom images as the target screen for image matching tasks, enabling users to test recognition pipelines against static images without needing a live controller connection.
Key Changes:
- Introduces a
MyCustomControllerclass that implementsCustomControllerto use uploaded images as screenshot sources - Adds a new "Custom" tab in the web UI that allows users to upload image files
- Disables actions and clicks when using custom controllers to make tasks perform only image matching
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 11 comments.
| File | Description |
|---|---|
src/MaaDebugger/webpage/reco_page/__init__.py |
Updates import path for cvmat_to_image to use the refactored img_tools module |
src/MaaDebugger/webpage/index_page/master_control.py |
Adds "Custom" controller tab with file upload functionality for image-based matching |
src/MaaDebugger/utils/img_tools.py |
Introduces rgb_to_bgr utility function for color channel conversion |
src/MaaDebugger/maafw/__init__.py |
Implements MyCustomController class and connect_custom_controller method; modifies task execution to disable actions for static images |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return False, f"Failed to connect {hex(_hwnd)}" | ||
|
|
||
| return True, None | ||
|
|
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The connect_custom_controller method is missing the @asyncify decorator that is present in other similar connection methods (connect_adb and connect_win32hwnd). This inconsistency could lead to issues if the method is called using await like the other connection methods in the UI code.
| @asyncify |
|
|
||
| return True, None | ||
|
|
||
| def connect_custom_controller(self, img_bytes) -> Tuple[bool, Optional[str]]: |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter name img_bytes lacks type annotation. Other connection methods in this class consistently use type annotations for their parameters. Add : bytes type annotation for consistency.
| def connect_custom_controller(self, img_bytes) -> Tuple[bool, Optional[str]]: | |
| def connect_custom_controller(self, img_bytes: bytes) -> Tuple[bool, Optional[str]]: |
| return ( | ||
| self.tasker.post_task(entry, pipeline_override).wait().succeeded, | ||
| None, | ||
| ) | ||
| else: | ||
| return ( | ||
| self.tasker.post_task(entry, pipeline_override).wait().succeeded, | ||
| None, | ||
| ) |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's code duplication in the if-else branches. Both branches return identical values (self.tasker.post_task(entry, pipeline_override).wait().succeeded, None). The logic can be simplified by updating pipeline_override conditionally before a single post_task call:
if isinstance(self.controller, CustomController):
# disable action
pipeline_override.update(
{entry: {"action": {"type": "DoNothing"}, "next": []}}
)
return (
self.tasker.post_task(entry, pipeline_override).wait().succeeded,
None,
)| return ( | |
| self.tasker.post_task(entry, pipeline_override).wait().succeeded, | |
| None, | |
| ) | |
| else: | |
| return ( | |
| self.tasker.post_task(entry, pipeline_override).wait().succeeded, | |
| None, | |
| ) | |
| return ( | |
| self.tasker.post_task(entry, pipeline_override).wait().succeeded, | |
| None, | |
| ) |
| GlobalStatus.ctrl_connecting = Status.SUCCEEDED | ||
|
|
||
| StatusIndicator(GlobalStatus, "ctrl_connecting") | ||
| ui.upload(auto_upload=True, on_upload=lambda e: on_upload(e)) |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ui.upload component should specify accepted file types to prevent users from uploading non-image files. Consider adding the accept parameter with image MIME types, e.g., ui.upload(auto_upload=True, on_upload=lambda e: on_upload(e), accept="image/*").
| ui.upload(auto_upload=True, on_upload=lambda e: on_upload(e)) | |
| ui.upload(auto_upload=True, on_upload=lambda e: on_upload(e), accept="image/*") |
| ui.notify( | ||
| f"Failed to load image. {e}", position="bottom-right", type="negative" | ||
| ) |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message is too generic. When image loading fails, users would benefit from more specific information about what went wrong (e.g., "unsupported image format", "corrupted image file", "image too large"). Consider catching specific exceptions (like PIL.UnidentifiedImageError) and providing tailored error messages.
| self.controller.post_connection().wait() | ||
|
|
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The connect_custom_controller method doesn't check the connection result like connect_adb and connect_win32hwnd do. Those methods verify post_connection().wait().succeeded and return failure status if unsuccessful. This method should similarly validate the connection and handle failure cases.
| self.controller.post_connection().wait() | |
| connected = self.controller.post_connection().wait().succeeded | |
| if not connected: | |
| return False, "Failed to connect custom controller" |
| except Exception as e: | ||
| GlobalStatus.ctrl_connecting = Status.FAILED | ||
| ui.notify( | ||
| f"Failed to load image. {e}", position="bottom-right", type="negative" |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable name e shadows the upload event parameter from the outer scope. The exception should be given a different name to avoid confusion and improve code clarity. Consider using ex or err for the exception variable.
| except Exception as e: | |
| GlobalStatus.ctrl_connecting = Status.FAILED | |
| ui.notify( | |
| f"Failed to load image. {e}", position="bottom-right", type="negative" | |
| except Exception as ex: | |
| GlobalStatus.ctrl_connecting = Status.FAILED | |
| ui.notify( | |
| f"Failed to load image. {ex}", position="bottom-right", type="negative" |
| from ..utils.img_tools import cvmat_to_image, rgb_to_bgr | ||
|
|
||
|
|
||
| class MyCustomController(CustomController): |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The MyCustomController class name doesn't follow the naming convention of the codebase. Since it's implementing a custom controller for static images, a more descriptive name like StaticImageController or UploadedImageController would better convey its purpose and be more consistent with framework naming patterns.
| class MyCustomController(CustomController): | |
| class StaticImageController(CustomController): |
| def request_uuid(self) -> str: | ||
| return "0" |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The request_uuid method returns a hardcoded "0" string. While this might be acceptable for a static image controller, consider documenting why this value is sufficient or using a more descriptive constant to clarify that UUIDs are not meaningful for static images.
| return self.tasker.post_task(entry, pipeline_override).wait().succeeded, None | ||
| if isinstance(self.controller, CustomController): | ||
| # disable action | ||
| pipeline_override.update( |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This expression mutates a default value.
#141
Summary by Sourcery
添加对使用自定义内存图像控制器和 UI 工作流上传图像作为匹配目标屏幕的支持。
新功能:
增强:
Original summary in English
Summary by Sourcery
Add support for using a custom in-memory image controller and UI workflow to upload an image as the target screen for matching.
New Features:
Enhancements: