feat(FishNew): 新增钓鱼预期收益识别#244
Conversation
Reviewer's Guide添加钓鱼结果日志记录和收益估算功能:在结算界面通过 OCR 识别鱼名,将其与价格表进行模糊匹配来累积贝壳收益,通过 focus 向前端流式推送每次捕获的更新,并在任务结束时汇报最终汇总结果;该功能已接入 FishNew 流水线并注册为自定义动作。 单次捕获日志记录与 focus 推送的时序图sequenceDiagram
participant FishNewPipeline as FishNew_pipeline
participant FishCatchLogger as FishCatchLogger
participant Context as Context
participant Controller as TaskController
participant Frontend as Frontend
FishNewPipeline->>FishCatchLogger: run(context, argv)
FishCatchLogger->>FishCatchLogger: reset() [first call]
FishCatchLogger->>Controller: post_screencap()
Controller-->>FishCatchLogger: image
FishCatchLogger->>Context: run_recognition(FishCatchLogger_OCR_FishName, image, pipeline_override)
Context-->>FishCatchLogger: reco_detail
FishCatchLogger->>FishCatchLogger: _fuzzy_match(ocr_text, price_table_keys)
FishCatchLogger->>Context: override_pipeline(FishCatchLogger_Notify)
FishCatchLogger->>Context: run_task(FishCatchLogger_Notify)
Context-->>Frontend: focus Node.Action.Succeeded(content=msg)
FishCatchLogger->>Controller: post_click_key(27)
FishCatchLogger-->>FishNewPipeline: RunResult(success=True)
最终汇总上报的时序图sequenceDiagram
participant FishNewPipeline as FishNew_pipeline
participant FishCatchSummary as FishCatchSummary
participant FishCatchLogger as FishCatchLogger
participant Context as Context
participant Frontend as Frontend
FishNewPipeline->>FishCatchSummary: run(context, argv)
FishCatchSummary->>FishCatchLogger: get_summary()
FishCatchLogger-->>FishCatchSummary: summary_text
FishCatchSummary->>Context: override_pipeline(FishCatchSummary_Notify)
FishCatchSummary->>Context: run_task(FishCatchSummary_Notify)
Context-->>Frontend: focus Node.Action.Succeeded(content=summary_text)
FishCatchSummary->>FishCatchLogger: reset()
FishCatchSummary->>FishCatchLogger: _initialized = False
FishCatchSummary-->>FishNewPipeline: RunResult(success=True)
文件级变更
Tips and commandsInteracting with Sourcery
Customizing Your Experience前往你的 dashboard 以:
Getting HelpOriginal review guide in EnglishReviewer's GuideAdds a fishing result logging and revenue estimation feature: OCRs fish names on the result screen, fuzzy-matches them to a price table to accumulate shell revenue, streams per-catch updates to the frontend via focus, and reports a final summary at task end, wired into the FishNew pipeline and registered as custom actions. Sequence diagram for per-catch logging and focus pushsequenceDiagram
participant FishNewPipeline as FishNew_pipeline
participant FishCatchLogger as FishCatchLogger
participant Context as Context
participant Controller as TaskController
participant Frontend as Frontend
FishNewPipeline->>FishCatchLogger: run(context, argv)
FishCatchLogger->>FishCatchLogger: reset() [first call]
FishCatchLogger->>Controller: post_screencap()
Controller-->>FishCatchLogger: image
FishCatchLogger->>Context: run_recognition(FishCatchLogger_OCR_FishName, image, pipeline_override)
Context-->>FishCatchLogger: reco_detail
FishCatchLogger->>FishCatchLogger: _fuzzy_match(ocr_text, price_table_keys)
FishCatchLogger->>Context: override_pipeline(FishCatchLogger_Notify)
FishCatchLogger->>Context: run_task(FishCatchLogger_Notify)
Context-->>Frontend: focus Node.Action.Succeeded(content=msg)
FishCatchLogger->>Controller: post_click_key(27)
FishCatchLogger-->>FishNewPipeline: RunResult(success=True)
Sequence diagram for final summary reportingsequenceDiagram
participant FishNewPipeline as FishNew_pipeline
participant FishCatchSummary as FishCatchSummary
participant FishCatchLogger as FishCatchLogger
participant Context as Context
participant Frontend as Frontend
FishNewPipeline->>FishCatchSummary: run(context, argv)
FishCatchSummary->>FishCatchLogger: get_summary()
FishCatchLogger-->>FishCatchSummary: summary_text
FishCatchSummary->>Context: override_pipeline(FishCatchSummary_Notify)
FishCatchSummary->>Context: run_task(FishCatchSummary_Notify)
Context-->>Frontend: focus Node.Action.Succeeded(content=summary_text)
FishCatchSummary->>FishCatchLogger: reset()
FishCatchSummary->>FishCatchLogger: _initialized = False
FishCatchSummary-->>FishNewPipeline: RunResult(success=True)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - 我发现了两个问题,并给出了一些整体性的反馈:
- 在 FishCatchLogger 中使用类级别的可变状态(例如
_total_count、_catch_log、_initialized)使得逻辑实际上是全局的;建议将这些计数器与任务/会话 ID 或实例状态绑定,以避免跨任务相互影响以及潜在的并发问题。 fish_catch_logger和fish_catch_summary在错误报告时都直接使用print;如果项目中已经有日志系统,建议通过日志器输出这些错误,以便在生产环境中更容易监控和过滤。- 在
_recognize_fish_name中,OCR 的 ROI 和 pipeline 的 override 是硬编码的;如果后续会有不同的分辨率或 UI 变体,建议从配置或 JSON pipeline 中读取这些设置,这样在布局调整时就不需要修改 Python 代码。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The use of class-level mutable state in FishCatchLogger (e.g., _total_count, _catch_log, _initialized) makes the logic effectively global; consider tying the counters to a task/session identifier or instance state to avoid cross-task interference and potential concurrency issues.
- Both fish_catch_logger and fish_catch_summary use bare `print` for error reporting; if the project has a logging facility, routing these errors through the logger would make them easier to monitor and filter in production.
- In _recognize_fish_name, the OCR ROI and pipeline override are hardcoded; if different resolutions or UI variants are expected, consider reading these settings from configuration or the JSON pipeline to avoid having to change Python code for layout tweaks.
## Individual Comments
### Comment 1
<location path="agent/custom/action/AutoFish/fish_catch_logger.py" line_range="134" />
<code_context>
+
+ return CustomAction.RunResult(success=True)
+
+ def _recognize_fish_name(self, context: Context, image) -> str:
+ """OCR 识别鱼名,并模糊匹配到价格表"""
+ reco_detail = context.run_recognition(
</code_context>
<issue_to_address>
**issue:** The return type annotation should include `None` to match the actual return values.
This method returns `None` in some cases (e.g. empty OCR text or no fuzzy match), but its signature is `-> str`. Update the annotation to `-> str | None` (or `Optional[str]`) so it accurately reflects the possible return values for type checkers and IDEs.
</issue_to_address>
### Comment 2
<location path="agent/custom/action/AutoFish/fish_catch_logger.py" line_range="18-20" />
<code_context>
+
+
+# 价格表路径
+_PRICE_TABLE_PATH = Path(__file__).parents[4] / "assets" / "resource" / "base" / "fish_price_table.json"
+if not _PRICE_TABLE_PATH.exists():
+ _PRICE_TABLE_PATH = Path(__file__).parents[4] / "resource" / "base" / "fish_price_table.json"
+
+# 加载价格表
</code_context>
<issue_to_address>
**suggestion:** When neither price table path exists, the code fails silently and uses an empty table.
If both paths are missing, `_load_price_table` returns `{}` without any signal, so all prices default to 0 and configuration/deployment issues are easy to miss. Please add a log or warning when no price table file is found so such misconfigurations are visible.
Suggested implementation:
```python
import json
import logging
from pathlib import Path
```
```python
def _load_price_table() -> dict:
"""加载价格表,返回 {鱼名: avg价格} 的扁平dict"""
if not _PRICE_TABLE_PATH.exists():
logging.warning(
"Fish price table file not found at expected locations, using empty price table. "
"Please check deployment configuration."
)
return {}
with open(_PRICE_TABLE_PATH, "r", encoding="utf-8") as f:
raw = json.load(f)
result = {}
for name, val in raw.items():
if isinstance(val, dict):
result[name] = val.get("avg", 0)
else:
```
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码评审。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- The use of class-level mutable state in FishCatchLogger (e.g., _total_count, _catch_log, _initialized) makes the logic effectively global; consider tying the counters to a task/session identifier or instance state to avoid cross-task interference and potential concurrency issues.
- Both fish_catch_logger and fish_catch_summary use bare
printfor error reporting; if the project has a logging facility, routing these errors through the logger would make them easier to monitor and filter in production. - In _recognize_fish_name, the OCR ROI and pipeline override are hardcoded; if different resolutions or UI variants are expected, consider reading these settings from configuration or the JSON pipeline to avoid having to change Python code for layout tweaks.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The use of class-level mutable state in FishCatchLogger (e.g., _total_count, _catch_log, _initialized) makes the logic effectively global; consider tying the counters to a task/session identifier or instance state to avoid cross-task interference and potential concurrency issues.
- Both fish_catch_logger and fish_catch_summary use bare `print` for error reporting; if the project has a logging facility, routing these errors through the logger would make them easier to monitor and filter in production.
- In _recognize_fish_name, the OCR ROI and pipeline override are hardcoded; if different resolutions or UI variants are expected, consider reading these settings from configuration or the JSON pipeline to avoid having to change Python code for layout tweaks.
## Individual Comments
### Comment 1
<location path="agent/custom/action/AutoFish/fish_catch_logger.py" line_range="134" />
<code_context>
+
+ return CustomAction.RunResult(success=True)
+
+ def _recognize_fish_name(self, context: Context, image) -> str:
+ """OCR 识别鱼名,并模糊匹配到价格表"""
+ reco_detail = context.run_recognition(
</code_context>
<issue_to_address>
**issue:** The return type annotation should include `None` to match the actual return values.
This method returns `None` in some cases (e.g. empty OCR text or no fuzzy match), but its signature is `-> str`. Update the annotation to `-> str | None` (or `Optional[str]`) so it accurately reflects the possible return values for type checkers and IDEs.
</issue_to_address>
### Comment 2
<location path="agent/custom/action/AutoFish/fish_catch_logger.py" line_range="18-20" />
<code_context>
+
+
+# 价格表路径
+_PRICE_TABLE_PATH = Path(__file__).parents[4] / "assets" / "resource" / "base" / "fish_price_table.json"
+if not _PRICE_TABLE_PATH.exists():
+ _PRICE_TABLE_PATH = Path(__file__).parents[4] / "resource" / "base" / "fish_price_table.json"
+
+# 加载价格表
</code_context>
<issue_to_address>
**suggestion:** When neither price table path exists, the code fails silently and uses an empty table.
If both paths are missing, `_load_price_table` returns `{}` without any signal, so all prices default to 0 and configuration/deployment issues are easy to miss. Please add a log or warning when no price table file is found so such misconfigurations are visible.
Suggested implementation:
```python
import json
import logging
from pathlib import Path
```
```python
def _load_price_table() -> dict:
"""加载价格表,返回 {鱼名: avg价格} 的扁平dict"""
if not _PRICE_TABLE_PATH.exists():
logging.warning(
"Fish price table file not found at expected locations, using empty price table. "
"Please check deployment configuration."
)
return {}
with open(_PRICE_TABLE_PATH, "r", encoding="utf-8") as f:
raw = json.load(f)
result = {}
for name, val in raw.items():
if isinstance(val, dict):
result[name] = val.get("avg", 0)
else:
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
||
| return CustomAction.RunResult(success=True) | ||
|
|
||
| def _recognize_fish_name(self, context: Context, image) -> str: |
There was a problem hiding this comment.
issue: 返回类型注解应包含 None,以匹配实际返回值。
该方法在某些情况下会返回 None(例如 OCR 文本为空或模糊匹配失败),但当前函数签名为 -> str。请将注解更新为 -> str | None(或 Optional[str]),以便类型检查器和 IDE 能够准确反映所有可能的返回值。
Original comment in English
issue: The return type annotation should include None to match the actual return values.
This method returns None in some cases (e.g. empty OCR text or no fuzzy match), but its signature is -> str. Update the annotation to -> str | None (or Optional[str]) so it accurately reflects the possible return values for type checkers and IDEs.
|
概述
新增钓鱼预期收益识别功能,在钓鱼结果界面自动 OCR 识别鱼名,模糊匹配价格表累计贝壳收益,通过 focus 实时推送到前端。
改动内容
fish_catch_logger.py:OCR 识别鱼名 + 编辑距离模糊匹配 + 累计贝壳收益 + focus 推送fish_price_table.json:鱼类价格表FishNew.jsonpipeline:钓鱼结果节点接入fish_catch_logger,任务结束调用fish_catch_summary汇总__init__.py:注册新 action效果
前端实时显示:第X条 XX鱼,累计预期收益XX贝壳
Summary by Sourcery
添加钓鱼结果日志动作:从结算界面 OCR 鱼名,与价格表匹配以估算贝壳收益,并将逐次捕获更新和最终汇总推送到前端。
New Features:
FishCatchLogger自定义动作,用于从钓鱼结算界面 OCR 获取鱼名,与价格表进行模糊匹配,累积捕获数量和预估贝壳收益,并向前端发送实时通知。FishCatchSummary自定义动作,用于在任务结束时向前端报告总捕获数量和预估贝壳收益的汇总信息。Enhancements:
FishNew钓鱼流水线中,以支持逐次捕获日志记录和任务结束时的结果汇总。Original summary in English
Summary by Sourcery
Add fishing result logging actions that OCR fish names from result screens, match them against a price table to estimate shell revenue, and push both per-catch updates and a final summary to the frontend.
New Features:
Enhancements: