Skip to content

Merge:'fix/RedDot-Log&v2'| 二值化红点v2识别 & 补全maa回调。#299

Open
sunyink wants to merge 5 commits into
mainfrom
fix/RedDot-Log&v2
Open

Merge:'fix/RedDot-Log&v2'| 二值化红点v2识别 & 补全maa回调。#299
sunyink wants to merge 5 commits into
mainfrom
fix/RedDot-Log&v2

Conversation

@sunyink
Copy link
Copy Markdown
Owner

@sunyink sunyink commented Jun 5, 2026

Summary by Sourcery

优化红点(通知)检测器,引入基于置信度的评分模型,提供更丰富的诊断信息和常驻的调试产物,并改进预设/独立模式下的行为以及错误报告。

Enhancements:

  • 将基于硬阈值的感叹号检测替换为多因素置信度评分模型,综合利用间距、纵横比、颜色对比度和居中程度等因素。
  • 为红点检测增加结构化的失败诊断、日志记录以及限速的调试图像导出,并支持通过环境变量配置日志目录。
  • 统一预设与独立识别流程,使预设调用能够复用独立模式的诊断能力,同时返回结构化的命中/未命中细节。
  • 改进红点检测器的错误处理机制,在发生异常时返回结构化的 AnalyzeResult 详情,而不是简单返回 None。
Original summary in English

Summary by Sourcery

Refine the red-dot (notification) detector to use a confidence-based scoring model with richer diagnostics and always-on debug artifacts, and improve preset/standalone behavior and error reporting.

Enhancements:

  • Replace hard-threshold exclamation detection with a multi-factor confidence scoring model combining gap, aspect ratio, color contrast, and centering.
  • Add structured failure diagnostics, logging, and rate-limited debug image dumps for red-dot detection, including environment-configurable log directories.
  • Unify preset and standalone recognition flows so preset calls reuse standalone diagnostics while returning structured hit/miss details.
  • Improve error handling in the red-dot detector by returning structured AnalyzeResult details instead of bare None on exceptions.

Summary by CodeRabbit

发布说明

  • 新功能

    • 红点检测升级为基于置信度加权的新识别流程,提升命中判定稳定性。
    • 预设检测现在返回带偏移的框与预设信息,并在未命中时提供结构化的提示与统计。
    • 增强调试落盘:保存关键调试图像并对落盘频率做节流管理。
  • Bug 修复

    • 异常时返回结构化错误详情,便于排查。
  • Chores

    • 更新红点检测配置与若干 ROI 参数。

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

RedDotDetector 从绝对阈值迁移为分项归一化置信度加权(min_confidence),重写预设/独立执行路径、异常返回为结构化 AnalyzeResult、新增置信度/诊断计算与按 key 节流的调试落盘功能。

Changes

RedDotDetector 置信度加权模型重设计

Layer / File(s) Summary
文档与模型架构
agent/recognition/binarymatch.py (322-369, 379-385, 395-535, 594-594)
更新顶层说明与示例配置,改为说明独立/预设两种模式、min_confidence 驱动的置信度加权(gap/vert/white/cent)与结构化失败字段。
参数与日志目录解析
agent/recognition/binarymatch.py (544-585)
新增加权常量 _W_*、默认阈值 _DEFAULT_MIN_CONF、节流常量 _DUMP_MIN_INTERVAL,并实现 _resolve_log_dir() 以解析调试根目录。
异常返回与调用者追踪
agent/recognition/binarymatch.py (601-606, 616-620)
analyze 异常分支由返回 None 改为返回 AnalyzeResult(box=None, detail={"result":"error", ...});引入 self._caller 用于暂存调用者节点名与原始 ROI。
预设模式实现
agent/recognition/binarymatch.py (632-666)
_run_preset 在裁剪 ROI 后写入 self._caller,通过 context.run_recognition 调用预设;命中时将 preset 框叠加 ROI 偏移并返回带 preset detail,未命中返回结构化 miss@preset(含 preset/roi/preset_detail/hint)。
独立模式核心算法
agent/recognition/binarymatch.py (690-882)
全面重写 _run_standalone:ROI 上 HSV→红色掩膜→连通域过滤→计算拓扑封闭的 enclosed 内部区;对每个候选计算 _exclamation_info_confidence,若 conf>=min_confidence 返回命中,否则汇总 stat 并进入诊断与失败落盘流程。
置信度计算与诊断出口
agent/recognition/binarymatch.py (771-809, 814-853, 858-871, 872-882)
新增 _exclamation_info(垂直投影与断层/段结构)、_whiteness/_confidence(四分项归一并加权返回 parts/conf)、_diagnose(根据 stat 映射 stage/hint)与 _miss(统一失败出口并返回结构化 detail)。
调试落盘与时间节流
agent/recognition/binarymatch.py (893-930)
新增 _img_key 生成稳定文件 key,重写 _save_debug_img(key,tag) 使用 _resolve_log_dir() 并按 key+tag 覆盖写入;新增 _dump_failure 按 key 与 _DUMP_MIN_INTERVAL 节流保存 roi_crop/red_mask/inner 调试图。
配置文件更新
assets/resource/base/pipeline/Test.json (699-699, 709-712)
RedDot_Preset 中新增 min_confidence: 0.25 并移除 inner_v_mininner_s_maxCheckPanel_Aroi 数值被更新以匹配新检测参数。

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题涉及红点v2识别与maa回调补全,与变更内容相关,但表述采用中文、分支名混用,且对主要变更点的说明不够直观。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/RedDot-Log&v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Jun 5, 2026

审查者指南

重构 RedDotDetector 识别流水线,改为使用带置信度评分的感叹号检测器,并增加更丰富的日志/遥测与自动调试图像导出,同时增强预设/独立模式的交互和错误处理。

文件级变更

变更 详情 文件
RedDotDetector 现在使用基于置信度的感叹号评分模型,带结构化诊断与自动调试图像导出,替代原先仅依赖阈值的垂直间隙检测。
  • 扩展并重写了文件顶部文档,说明新的置信度模型、参数集合(用 min_confidence 替代 inner_v_min/inner_s_max)、预设使用方式、可观测性以及调参工作流。
  • 引入全局加权常量、默认 min_confidence,以及日志目录解析辅助函数,包括环境变量覆盖和节流的调试导出配置。
  • 修改独立识别逻辑:先计算红色连通区域,再在不使用绝对 HSV 阈值的前提下提取内部非红区域,对每个候选区域通过综合间隙/纵横比/白度/居中度等指标打分,并基于 min_confidence 选择命中结果。
  • 新增 exclamation_info 和 confidence 辅助方法,为每个连通区域计算纵向投影、间隙统计、白度度量以及复合置信度分数。
  • 实现结构化失败路径,用于诊断失败阶段,记录简洁的面向 UI 的警告以及详细统计信息,并返回包含 result/mode/stage/hint/stat/params 等详细字段的 AnalyzeResult。
  • 重构预设模式处理逻辑,用于跟踪调用方节点/ROI,记录命中/未命中并提供更清晰的日志消息,同时返回包含预设名称和 ROI 的结构化详情。
  • 新增永久调试图像保存功能,将 roi_crop、red_mask 和最佳内部区域保存到解析得到的 debug/RedDotDetector 目录中,以节点+ROI 作为键进行时间节流并采用覆盖语义。
  • 改进 analyze 中的错误处理,在返回的 detail 中包含异常摘要,并通过 mfaalog.error() 记录完整的 traceback。
agent/recognition/binarymatch.py

提示与命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在某条审查评论下回复,要求 Sourcery 从该评论创建一个 issue。你也可以在审查评论中回复 @sourcery-ai issue 来从该评论创建一个 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成拉取请求概要: 在拉取请求正文的任意位置写上 @sourcery-ai summary,即可在你指定的位置随时生成 PR 概要。你也可以在拉取请求中评论 @sourcery-ai summary 来在任意时间(重新)生成概要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可在任意时间(重新)生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完全部评论且不想再看到它们,这会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你希望从头开始一次新的审查,这尤其有用——别忘了再次评论 @sourcery-ai review 以触发新的审查!

自定义你的体验

访问你的 控制面板 以:

  • 启用或禁用审查特性,例如 Sourcery 生成的拉取请求概要、审查者指南等。
  • 修改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

Refactors the RedDotDetector recognition pipeline to use a confidence-scored exclamation detector with richer logging/telemetry and automatic debug image dumping, and enhances preset/standalone interaction and error handling.

File-Level Changes

Change Details Files
RedDotDetector now uses a confidence-based exclamation scoring model with structured diagnostics and automatic debug image dumping, replacing the old threshold-only vertical gap check.
  • Expanded and rewrote the top-of-file documentation to describe the new confidence model, parameter set (min_confidence replacing inner_v_min/inner_s_max), preset usage, observability, and tuning workflow.
  • Introduced global weighting constants, default min_confidence, and log directory resolution helpers, including environment-variable overrides and throttled debug-dump configuration.
  • Changed standalone recognition to compute red blobs, extract enclosed non-red interiors without absolute HSV thresholds, score each candidate via combined gap/aspect/whiteness/centering metrics, and select hits based on min_confidence.
  • Added exclamation_info and confidence helper methods that derive vertical projections, gap statistics, whiteness measures, and a composite confidence score for each blob.
  • Implemented a structured failure path that diagnoses which stage failed, logs concise UI-facing warnings plus detailed stats, and returns AnalyzeResult with result/mode/stage/hint/stat/params in detail.
  • Reworked preset-mode handling to track the caller node/ROI, log hits/misses with clearer messages, and return structured detail including preset name and ROI.
  • Added permanent debug image saving for roi_crop, red_mask, and best inner region into a resolved debug/RedDotDetector directory, keyed by node+ROI with per-key time throttling and overwrite semantics.
  • Improved error handling in analyze to include the exception summary in the returned detail and to log the full traceback via mfaalog.error().
agent/recognition/binarymatch.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嘿,我已经审查了你的更改,看起来很棒!


Sourcery 对开源项目是免费的——如果你喜欢我们的代码审查,请考虑分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
assets/resource/base/pipeline/Test.json (1)

668-714: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

清理仍在使用的 RedDotDetector 旧参数:Agt_RedDot_Preset 仍包含 inner_v_min/inner_s_max
assets/resource/base/pipeline/Dummy.json 里,Agt_RedDot_Presetcustom_recognition_param 仍使用了 inner_v_min / inner_s_max(位于预设参数中)。而 Test.jsonRedDot_Preset 已按 v2 模型迁移到 min_confidence,文档明确该模式“不再依赖 removed inner_v_min / inner_s_max thresholds”。当前多处节点仍引用 {"preset":"Agt_RedDot_Preset"}(如 QuestList.jsonPass.jsonMail.jsonGACHA.jsonGACHA_ADV.json 等),因此这些节点的红点检测很可能不会按 v2 期望的门限生效;需要把 Agt_RedDot_Preset 也迁移到 min_confidence 模型并统一参数集。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/resource/base/pipeline/Test.json` around lines 668 - 714, The
Agt_RedDot_Preset still uses removed thresholds inner_v_min/inner_s_max while
RedDot_Preset has been migrated to the v2 style (min_confidence, gap_ratio,
red_area, hsv_ranges, debug); update the Agt_RedDot_Preset definition to the
same v2 parameter set (replace inner_v_min/inner_s_max with min_confidence and
include gap_ratio, red_area, hsv_ranges, debug as in RedDot_Preset) and then
verify/adjust every node that references {"preset":"Agt_RedDot_Preset"} (e.g.,
nodes similar to CheckPanel_A) to either point to the updated Agt_RedDot_Preset
or to RedDot_Preset so all red-dot detections use the unified
min_confidence-based thresholds.
🧹 Nitpick comments (1)
agent/recognition/binarymatch.py (1)

398-403: ⚡ Quick win

示例里的 CheckPanel_A.roi 还是旧值。

这里的示例 B 仍然写着 [640, 616, 17, 16],但这次 PR 引用的配置说明已经把 CheckPanel_A 的 ROI 更新成 [723, 616, 18, 18]。这段注释本身就是调参文档,继续保留旧坐标会把后续对照示例的人直接带偏。建议同步成当前示例值,或至少明确标注这是占位示例。

As per coding guidelines, "CheckPanel_A: roi changed to [723, 616, 18, 18]; ensure this ROI matches the expected red-dot search region since the detector now crops ROI and applies the new internal blob/confidence logic."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` around lines 398 - 403, The example comment
contains an outdated ROI for CheckPanel_A (still [640, 616, 17, 16]); update the
example to the new value [723, 616, 18, 18] (or explicitly mark it as a
placeholder) so the inline documentation matches the current detector behavior;
specifically edit the commented example for "CheckPanel_A" in binarymatch.py to
set CheckPanel_A.roi to [723, 616, 18, 18] and, if helpful, add a short note
that RedDotDetector now crops the ROI and uses the new internal blob/confidence
logic to avoid confusion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agent/recognition/binarymatch.py`:
- Around line 633-650: The code currently conflates reco is None (recognition
not started) with reco.hit == False (recognition ran but missed); update the
logic around Context.run_recognition/preset handling so you first check if reco
is None and return a distinct AnalyzeResult indicating the recognition did not
start (include context like preset_node and any available status), and only if
reco is non-None then branch on reco.hit; when reco.hit is False, return
CustomRecognition.AnalyzeResult(box=None, detail=...) but propagate the preset
node's raw_detail (e.g., reco.raw_detail) into the returned detail along with
result:"miss" and existing roi/hint fields so upstream can see stage/hint/stat
from the preset node rather than masking configuration errors as ordinary
misses.
- Around line 553-555: The module currently parses RDD_DUMP_INTERVAL at import
time into _DUMP_MIN_INTERVAL which can raise ValueError and abort import
(preventing RedDotDetector registration); change this to parse/validate with a
safe fallback at runtime (e.g., in the RedDotDetector initializer or before
first use) or wrap the environment parsing in a try/except that falls back to a
sane default and logs the parse error; ensure the symbol _DUMP_MIN_INTERVAL is
assigned only after validation so imports never raise, and reference
RDD_DUMP_INTERVAL, _DUMP_MIN_INTERVAL, and RedDotDetector (and analyze() if
relevant) when updating the code paths.

---

Outside diff comments:
In `@assets/resource/base/pipeline/Test.json`:
- Around line 668-714: The Agt_RedDot_Preset still uses removed thresholds
inner_v_min/inner_s_max while RedDot_Preset has been migrated to the v2 style
(min_confidence, gap_ratio, red_area, hsv_ranges, debug); update the
Agt_RedDot_Preset definition to the same v2 parameter set (replace
inner_v_min/inner_s_max with min_confidence and include gap_ratio, red_area,
hsv_ranges, debug as in RedDot_Preset) and then verify/adjust every node that
references {"preset":"Agt_RedDot_Preset"} (e.g., nodes similar to CheckPanel_A)
to either point to the updated Agt_RedDot_Preset or to RedDot_Preset so all
red-dot detections use the unified min_confidence-based thresholds.

---

Nitpick comments:
In `@agent/recognition/binarymatch.py`:
- Around line 398-403: The example comment contains an outdated ROI for
CheckPanel_A (still [640, 616, 17, 16]); update the example to the new value
[723, 616, 18, 18] (or explicitly mark it as a placeholder) so the inline
documentation matches the current detector behavior; specifically edit the
commented example for "CheckPanel_A" in binarymatch.py to set CheckPanel_A.roi
to [723, 616, 18, 18] and, if helpful, add a short note that RedDotDetector now
crops the ROI and uses the new internal blob/confidence logic to avoid
confusion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3929bcfa-538f-4d64-8f5a-0d607d67042c

📥 Commits

Reviewing files that changed from the base of the PR and between f127c7b and f630e4f.

📒 Files selected for processing (2)
  • agent/recognition/binarymatch.py
  • assets/resource/base/pipeline/Test.json

Comment thread agent/recognition/binarymatch.py
Comment thread agent/recognition/binarymatch.py
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 5, 2026

🤖 DeepSeek 自动评审报告

模型deepseek-v4-pro 触发workflow_dispatch Diff 截断:否 输出截断:否 参考资料截断:否 改动文件:2(二进制跳过 0)

概览

PR #299 将红点检测器(RedDotDetector)从原先基于硬阈值(inner_v_min/inner_s_max 等)的“感叹号双段判定”升级为基于置信度加权的抗模糊模型,并在预设/独立两种模式下统一了可观测性(结构化 detail、常驻失败截图、日志)。算法逻辑本身有充分论证,代码结构清晰,但存在两个直接影响 MaaFW 流程控制的关键错误,必须修正后才能合入。


阻塞性问题(必须修改)

1. 未命中时返回 AnalyzeResult(box=None) 而非 None,导致流程控制错误

  • 文件agent/recognition/binarymatch.py —— _run_preset 未命中分支、_miss 方法、异常处理
  • 相同问题出现位置(共 3 处):
    1. _run_preset 未命中时返回 CustomRecognition.AnalyzeResult(box=None, detail={...})
    2. _miss 方法末尾返回 CustomRecognition.AnalyzeResult(box=None, detail=...)
    3. analyzeexcept 块返回 CustomRecognition.AnalyzeResult(box=None, detail={...})
  • 影响范围
    • 所有使用 RedDotDetector 的节点(包括通过 preset 调用的节点)。当未识别到红点时,MaaFW 接收到 AnalyzeResult(box=None) 后会认为“识别已命中”(hit),进而可能执行节点的 action(例如 Click)并直接转入该节点的 next 列表。这破坏了 next 列表的顺序检测循环,导致本应继续等待或尝试下一个识别项的流程被错误地“通过”,最终造成漏检、误点击或流程提前终止。
    • 异常情况同样会被当作“命中”处理,掩盖真实错误。
  • 原因
    • MaaFW 协议规定:自定义识别回调 应返回 AnalyzeResult(box, detail) 表示识别成功,或返回 None 表示未找到目标(见《算法类型 - Custom》)。
    • box=NoneAnalyzeResult 并不等于“未命中”;MaaFW 会将其视为一次有效的识别结果并进入后继流程,而非继续识别 next 或等待超时。
  • 修复
    • 将所有“未命中”路径改为 return None,同时可通过日志输出 detail 信息以供诊断,但不得把这些信息包装成非空 AnalyzeResult 返回给框架。
    • 具体修改:
      1. _run_preset 未命中分支:直接 return None(或先 mfaalog.warning(...)return None)。
      2. _miss 方法:去掉 return CustomRecognition.AnalyzeResult(box=None, detail=...),改为先 mfaalog.warning(...) / print(...),然后 return None
      3. analyze 异常处理:return None(保留 error 日志),不要返回含 detail 的 AnalyzeResult。
    • 保留 detail 中的诊断数据仅用于日志和调试,不影响 MaaFW 的流程判定。

建议改进(非阻塞)

1. 废弃参数 inner_v_min / inner_s_max 的兼容性风险

  • 文件agent/recognition/binarymatch.py(新代码不再使用这些参数);assets/resource/base/pipeline/Test.json(已更新参数)
  • 问题:新版 RedDotDetector 已移除对 inner_v_mininner_s_max 的所有引用,但本次 diff 仅修改了 Test.json 中的 RedDot_Preset 节点。如果项目其他 pipeline JSON 文件中仍存在使用旧版参数的 RedDotDetector 节点,这些节点将无法工作(参数被忽略,识别可能失控)。
  • 影响范围:所有使用旧参数但未同步更新的 RedDotDetector pipeline 节点。
  • 修复
    • 在 PR 中一并修改所有引用 RedDotDetector 的 pipeline 节点,将 inner_v_min / inner_s_max 替换为 min_confidence(或移除它们)。
    • 或在 _run_standalone 中增加兼容性提示:如果检测到旧参数,打印 warning 并使用默认值作为兜底(如果希望过渡)。但鉴于该识别器是重写,建议强制要求所有调用方更新参数,并在这份 PR 中完成修改。
    • 如果确实不便一次性修改,至少需要在代码中检测旧参数并抛出明确错误,避免静默失效。

疑问 / 需要作者确认

1. argv.node_name 是否在所有 MaaFW 场景中都可用?

  • 位置_run_standalone_run_preset 中对 getattr(argv, "node_name", "") 的使用。
  • 说明:MaaFW 的 AnalyzeArg 文档中未列出 node_name 属性,本项目可能依赖了特定 MaaFW 版本的扩展字段。若无此属性,截图 key 会变为空字符串,各检测点的失败截图会相互覆盖,但不会导致崩溃。
  • 建议:确认当前使用的 MaaFW 版本是否提供该属性;若不提供,可改用 context.tasker 或其他方式获取当前节点名,或用 preset 调用方传递的节点名作为 fallback。

2. _resolve_log_dir 的目录判定能否保证在各类部署环境下正确?

  • 位置:模块顶部的 _resolve_log_dir 函数,依据 CWD 下是否存在 debug/config/ 目录来区分“用户侧”和“开发侧”日志根目录。
  • 疑问:MaaFW 运行时的 cwd 是否永远等于 interface.json 所在目录?在通过某些启动器或容器化部署时可能不同。环境变量 RDD_DEBUG_DIR 可作为安全 fallback,但若忘记设置,截图可能写入错误路径或根目录。
  • 建议:补充文档说明部署时应在何处设置 RDD_DEBUG_DIR,或考虑从 maa.log 的实际路径反推日志目录(如果 MaaFW 提供了对应接口),以提高健壮性。

以上阻塞问题 1 属于 CI 无法检测的逻辑错误,必须修改;建议 1 可能引发线上失效,建议一并处理。其余代码在逻辑和数据流层面无明显缺陷。


由 GitHub Actions + DeepSeek 自动生成;以人工审查为准。

@sunyink
Copy link
Copy Markdown
Owner Author

sunyink commented Jun 5, 2026

🤖 DeepSeek 自动评审报告

模型deepseek-v4-pro 触发workflow_dispatch Diff 截断:否 输出截断:否 参考资料截断:否 改动文件:2(二进制跳过 0)

概览

PR #299 将红点检测器(RedDotDetector)从原先基于硬阈值(inner_v_min/inner_s_max 等)的“感叹号双段判定”升级为基于置信度加权的抗模糊模型,并在预设/独立两种模式下统一了可观测性(结构化 detail、常驻失败截图、日志)。算法逻辑本身有充分论证,代码结构清晰,但存在两个直接影响 MaaFW 流程控制的关键错误,必须修正后才能合入。

阻塞性问题(必须修改)

1. 未命中时返回 AnalyzeResult(box=None) 而非 None,导致流程控制错误

否决,与事实不符.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agent/recognition/binarymatch.py`:
- Around line 650-665: The preset-mode AnalyzeResult detail is inconsistent: the
hit branch (CustomRecognition.AnalyzeResult in this file around the preset
handling for variable preset_node) only returns {"result","preset"} while the
miss branch embeds the preset node's stage/stat/conf/parts under "preset_detail"
using reco.raw_detail; unify both branches to the same detail schema promised by
the file-level docs by extracting the preset node's stage/stat/conf/parts (from
getattr(reco, "raw_detail", None) or reco.raw_detail) into the same top-level
detail fields (e.g., stage, stat, conf, parts or a single "preset" object) for
both hit and miss, preserve existing keys like
"result","mode","preset","roi","hint", and ensure the hit branch includes the
same preset-related fields so downstream code (MaaLogs/tuning scripts) can rely
on one schema.
- Around line 554-557: The environment parsing for _DUMP_MIN_INTERVAL should
treat NaN, Infinity, and non-positive values as invalid; when reading
RDD_DUMP_INTERVAL (currently via os.environ.get in the module scope), parse with
float inside the existing try/except, then validate with math.isfinite(value)
and value > 0 and fallback to 2.0 if validation fails; keep the existing
exception handling (TypeError, ValueError) and ensure the final assigned symbol
is _DUMP_MIN_INTERVAL with the safe default.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a72b615-c5cd-483a-ae86-78d5db084686

📥 Commits

Reviewing files that changed from the base of the PR and between f630e4f and 3d325c8.

📒 Files selected for processing (1)
  • agent/recognition/binarymatch.py

Comment on lines +554 to +557
try:
_DUMP_MIN_INTERVAL = float(os.environ.get("RDD_DUMP_INTERVAL", "2.0"))
except (TypeError, ValueError):
_DUMP_MIN_INTERVAL = 2.0 # 环境变量非法时兜底,避免 import 阶段崩溃中断 Agent 启动
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import math

for raw in ("2.0", "nan", "inf", "-1", "oops"):
    try:
        value = float(raw)
        print(raw, "->", value, "isfinite=", math.isfinite(value), "negative=", value < 0)
    except Exception as exc:
        print(raw, "->", type(exc).__name__)
PY

Repository: sunyink/MFABD2

Length of output: 246


[minor] 让 RDD_DUMP_INTERVALnan/inf/负数 也视为非法并兜底(避免节流失效)

当前 float()RDD_DUMP_INTERVAL=nan/inf 会解析成功而不会触发 try/except(math.isfinite 为 False),后续节流比较可能失效;同时负数也会通过解析并反向影响节流语义。

🩹 建议补丁
+import math
 import json
 import re
 import time
 import os
 import traceback
@@
 try:
-    _DUMP_MIN_INTERVAL = float(os.environ.get("RDD_DUMP_INTERVAL", "2.0"))
+    _dump_min_interval = float(os.environ.get("RDD_DUMP_INTERVAL", "2.0"))
+    if not math.isfinite(_dump_min_interval) or _dump_min_interval < 0:
+        raise ValueError
+    _DUMP_MIN_INTERVAL = _dump_min_interval
 except (TypeError, ValueError):
     _DUMP_MIN_INTERVAL = 2.0   # 环境变量非法时兜底,避免 import 阶段崩溃中断 Agent 启动
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
_DUMP_MIN_INTERVAL = float(os.environ.get("RDD_DUMP_INTERVAL", "2.0"))
except (TypeError, ValueError):
_DUMP_MIN_INTERVAL = 2.0 # 环境变量非法时兜底,避免 import 阶段崩溃中断 Agent 启动
try:
_dump_min_interval = float(os.environ.get("RDD_DUMP_INTERVAL", "2.0"))
if not math.isfinite(_dump_min_interval) or _dump_min_interval < 0:
raise ValueError
_DUMP_MIN_INTERVAL = _dump_min_interval
except (TypeError, ValueError):
_DUMP_MIN_INTERVAL = 2.0 # 环境变量非法时兜底,避免 import 阶段崩溃中断 Agent 启动
🧰 Tools
🪛 Ruff (0.15.15)

[warning] 557-557: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` around lines 554 - 557, The environment
parsing for _DUMP_MIN_INTERVAL should treat NaN, Infinity, and non-positive
values as invalid; when reading RDD_DUMP_INTERVAL (currently via os.environ.get
in the module scope), parse with float inside the existing try/except, then
validate with math.isfinite(value) and value > 0 and fallback to 2.0 if
validation fails; keep the existing exception handling (TypeError, ValueError)
and ensure the final assigned symbol is _DUMP_MIN_INTERVAL with the safe
default.

Comment on lines +650 to +665
if reco.hit:
bx, by, bw, bh = reco.box
adjusted = (bx + rx, by + ry, bw, bh)
print(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
return CustomRecognition.AnalyzeResult(box=adjusted, detail={"preset": preset_node})
return None
mfaalog.info(f"[RedDotDetector] [preset:{preset_node}] hit -> {adjusted}")
return CustomRecognition.AnalyzeResult(
box=adjusted, detail={"result": "hit", "preset": preset_node})

# 真未命中:阶段原因已由预设节点(独立模式)记进嵌套识别记录;这里附带透传其 raw_detail
raw = getattr(reco, "raw_detail", None)
mfaalog.warning(f"[RedDotDetector] miss@preset | {argv.node_name} via {preset_node}")
return CustomRecognition.AnalyzeResult(box=None, detail={
"result": "miss", "mode": "preset", "preset": preset_node,
"roi": [rx, ry, rw, rh],
"preset_detail": raw,
"hint": "阶段原因见预设节点(独立模式)的 detail;失败截图见 debug/RedDotDetector/ 下以本节点名命名的 rdd_* 文件",
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

预设模式的 detail 还没有真正统一。

Line 654 只返回了 {"result", "preset"},Line 663 又把预设节点的 stage/stat/conf/parts 包进了 preset_detail。这样预设模式命中/未命中的 detail 结构都和本文件上方文档承诺的统一 detail.* schema 不一致,接入 MaaLogs 或调参脚本时还得额外分支判断,等于把这次 PR 想统一的 preset/standalone 契约又拆开了。

♻️ 建议补丁
         if reco.hit:
+            raw = getattr(reco, "raw_detail", None)
             bx, by, bw, bh = reco.box
             adjusted = (bx + rx, by + ry, bw, bh)
+            detail = raw.copy() if isinstance(raw, dict) else (
+                {"raw_detail": raw} if raw is not None else {}
+            )
+            detail.update({
+                "result": "hit",
+                "mode": "preset",
+                "preset": preset_node,
+                "roi": [rx, ry, rw, rh],
+                "box": list(adjusted),
+            })
             mfaalog.info(f"[RedDotDetector] [preset:{preset_node}] hit -> {adjusted}")
-            return CustomRecognition.AnalyzeResult(
-                box=adjusted, detail={"result": "hit", "preset": preset_node})
+            return CustomRecognition.AnalyzeResult(box=adjusted, detail=detail)

         # 真未命中:阶段原因已由预设节点(独立模式)记进嵌套识别记录;这里附带透传其 raw_detail
         raw = getattr(reco, "raw_detail", None)
+        detail = raw.copy() if isinstance(raw, dict) else (
+            {"raw_detail": raw} if raw is not None else {}
+        )
+        detail.update({
+            "result": "miss",
+            "mode": "preset",
+            "preset": preset_node,
+            "roi": [rx, ry, rw, rh],
+            "hint": "阶段原因见预设节点(独立模式)的 detail;失败截图见 debug/RedDotDetector/ 下以本节点名命名的 rdd_* 文件",
+        })
         mfaalog.warning(f"[RedDotDetector] miss@preset | {argv.node_name} via {preset_node}")
-        return CustomRecognition.AnalyzeResult(box=None, detail={
-            "result": "miss", "mode": "preset", "preset": preset_node,
-            "roi": [rx, ry, rw, rh],
-            "preset_detail": raw,
-            "hint": "阶段原因见预设节点(独立模式)的 detail;失败截图见 debug/RedDotDetector/ 下以本节点名命名的 rdd_* 文件",
-        })
+        return CustomRecognition.AnalyzeResult(box=None, detail=detail)
🧰 Tools
🪛 Ruff (0.15.15)

[warning] 657-657: Comment contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF003)


[warning] 657-657: Comment contains ambiguous (FULLWIDTH SEMICOLON). Did you mean ; (SEMICOLON)?

(RUF003)


[warning] 664-664: String contains ambiguous (FULLWIDTH SEMICOLON). Did you mean ; (SEMICOLON)?

(RUF001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` around lines 650 - 665, The preset-mode
AnalyzeResult detail is inconsistent: the hit branch
(CustomRecognition.AnalyzeResult in this file around the preset handling for
variable preset_node) only returns {"result","preset"} while the miss branch
embeds the preset node's stage/stat/conf/parts under "preset_detail" using
reco.raw_detail; unify both branches to the same detail schema promised by the
file-level docs by extracting the preset node's stage/stat/conf/parts (from
getattr(reco, "raw_detail", None) or reco.raw_detail) into the same top-level
detail fields (e.g., stage, stat, conf, parts or a single "preset" object) for
both hit and miss, preserve existing keys like
"result","mode","preset","roi","hint", and ensure the hit branch includes the
same preset-related fields so downstream code (MaaLogs/tuning scripts) can rely
on one schema.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant