feat: OCR 模型 v5 到 v6 平滑迁移 - #2681
Conversation
正常模式下 init_ocr 按本地文件状态向 V6 收敛: - 有 V6 直接用并落盘配置 - 有 V5 没 V6 先用 V5 顶住 后台下载 V6 成功后自动切换 - 都没有直接下载 V6 配置只在 V6 就绪后改写 下载失败时 V5 保持可用 调试模式下不自动切换 保留手动选择
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 Walkthrough变更
Walkthrough新增 OCR 模型文件完整性检查和 V5/V6 选择逻辑。正常模式优先使用已就绪的 V6。仅 V5 就绪时使用 V5,并后台下载 V6。下载成功后保存配置,失败时保留当前模型。 ChangesOCR 模型收敛
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant ZContext
participant onnx_ocr_matcher
participant OnnxOcrParam
participant OCR配置
ZContext->>onnx_ocr_matcher: 检查 V5/V6 模型文件
onnx_ocr_matcher-->>ZContext: 返回模型就绪状态
ZContext->>OnnxOcrParam: 传入选择后的模型名称
ZContext->>onnx_ocr_matcher: 启动 V6 后台下载
onnx_ocr_matcher-->>ZContext: 返回下载结果
ZContext->>OCR配置: 下载成功后保存 V6 配置
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/one_dragon/base/operation/one_dragon_context.py (1)
497-516: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift在 V6 初始化成功前保留当前 OCR 实例。
后台线程在 Line 581 调用
init_ocr()。该方法会在 Line 497-510 清理当前 V5 实例并替换服务引用,然后才在 Line 513-516 初始化候选 V6。如果
init_model()失败,异常只会被下载线程记录。旧 V5 已不可用,OcrService已指向未初始化的 V6 实例。下载成功不保证 ONNX session 初始化成功。请先初始化候选 OCR。初始化成功后,再通过受同步保护的切换操作更新
self.ocr、self.ocr_service.ocr_matcher和cv_service.ocr,最后清理旧实例。后台回调中的 ONNX 初始化必须通过gpu_executor.submit执行。As per coding guidelines, “GPU/ONNX session 的异步调用必须通过
gpu_executor.submit,不要并发直接调用多个 session”。Also applies to: 578-581
🤖 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 `@src/one_dragon/base/operation/one_dragon_context.py` around lines 497 - 516, 调整 init_ocr 及其后台回调流程:先创建并初始化候选 OnnxOcrMatcher,且所有 GPU/ONNX 初始化必须通过 gpu_executor.submit 执行;仅在 init_model 成功后,通过受同步保护的切换操作更新 self.ocr、self.ocr_service.ocr_matcher 和 cv_service.ocr,最后再清理旧 OCR 实例,初始化失败时保留现有实例及服务引用。Source: Coding guidelines
🧹 Nitpick comments (1)
src/one_dragon/base/operation/one_dragon_context.py (1)
553-553: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value使用
pathlib检查模型文件。此处新增了
os.path.exists()。本文件已经使用Path。请改为Path(file_path).exists(),并删除新增的os导入。建议修改
-import os - - return all(os.path.exists(f) for f in get_final_file_list(ocr_model_name)) + return all(Path(file_path).exists() for file_path in get_final_file_list(ocr_model_name))As per coding guidelines, “路径操作使用 pathlib”。
🤖 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 `@src/one_dragon/base/operation/one_dragon_context.py` at line 553, 在检查 OCR 模型文件的逻辑中,将 os.path.exists 调用替换为 Path(file_path).exists(),并移除新增但不再使用的 os 导入;保留 get_final_file_list 和 all 的现有行为。Source: Coding guidelines
🤖 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 `@src/one_dragon/base/operation/one_dragon_context.py`:
- Around line 527-589: 补充 OCR 迁移状态的单元测试和对应开发文档,覆盖 _decide_ocr_model_name 的调试模式、仅
V6 就绪、仅 V5 就绪及两者缺失场景,并覆盖 _download_ocr_v6_in_background 的下载失败、异常和成功后切换场景。验证 V6
下载完成后调用 init_ocr 失败时,仍能保留可用的 V5 OCR 配置,不因切换失败破坏现有能力;同步记录迁移行为与验证结果到开发文档。
---
Outside diff comments:
In `@src/one_dragon/base/operation/one_dragon_context.py`:
- Around line 497-516: 调整 init_ocr 及其后台回调流程:先创建并初始化候选 OnnxOcrMatcher,且所有
GPU/ONNX 初始化必须通过 gpu_executor.submit 执行;仅在 init_model 成功后,通过受同步保护的切换操作更新
self.ocr、self.ocr_service.ocr_matcher 和 cv_service.ocr,最后再清理旧 OCR
实例,初始化失败时保留现有实例及服务引用。
---
Nitpick comments:
In `@src/one_dragon/base/operation/one_dragon_context.py`:
- Line 553: 在检查 OCR 模型文件的逻辑中,将 os.path.exists 调用替换为
Path(file_path).exists(),并移除新增但不再使用的 os 导入;保留 get_final_file_list 和 all 的现有行为。
🪄 Autofix
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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: fcff4d74-e0f9-4c9c-bd7e-e9fa457107b3
📒 Files selected for processing (1)
src/one_dragon/base/operation/one_dragon_context.py
编程兔 review 指出: 立刻切换需先清理 V5 再初始化 V6, V6 初始化失败时 当前可用 V5 也丢了. 改为下载成功后只落盘配置, 下次启动 init_ocr 自然 用 V6, 本次会话始终稳定. 同时按规范将 os.path.exists 改为 Path.exists, 补充 OCR 模型选择行为文档.
|
@coderabbitai review |
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/one_dragon/base/operation/one_dragon_context.py (1)
494-503: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift先完成候选模型初始化,再替换当前 OCR。
Line 497-499会先清理当前self.ocr。Line 501-510又在init_model()成功前更新self.ocr、self.ocr_service和cv_service。如果 V6 文件存在但 ONNX session 初始化失败,init()只会记录异常,原本可用的 V5 已无法恢复。请先初始化候选 matcher。只有初始化成功后,才更新服务引用并清理旧实例。V6 初始化失败且 V5 文件就绪时,应回退到 V5。
🤖 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 `@src/one_dragon/base/operation/one_dragon_context.py` around lines 494 - 503, 调整 OCR 初始化流程:在替换当前 self.ocr、self.ocr_service 和 cv_service 前,先完成候选 OnnxOcrMatcher 的初始化并确认成功。仅在候选模型可用后清理旧 OCR 实例并更新服务引用;当 V6 初始化失败且 V5 文件就绪时,回退并使用 V5 模型,避免破坏现有可用实例。
🤖 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 `@src/one_dragon/base/operation/one_dragon_context.py`:
- Line 552: 更新 _is_ocr_model_ready() 的 OCR 模型就绪检查,使用 Path.is_file() 排除同名目录;同时按
OCR 模型实际必需的文件范围构造检查列表,确保必需的 _dict.txt 被纳入校验,不要仅依赖 get_final_file_list()
的条件性收集结果。
---
Outside diff comments:
In `@src/one_dragon/base/operation/one_dragon_context.py`:
- Around line 494-503: 调整 OCR 初始化流程:在替换当前 self.ocr、self.ocr_service 和 cv_service
前,先完成候选 OnnxOcrMatcher 的初始化并确认成功。仅在候选模型可用后清理旧 OCR 实例并更新服务引用;当 V6 初始化失败且 V5
文件就绪时,回退并使用 V5 模型,避免破坏现有可用实例。
🪄 Autofix
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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c9b4fa81-1189-4868-8e5b-e5074a62bda6
📒 Files selected for processing (2)
docs/develop/one_dragon/initialization.mdsrc/one_dragon/base/operation/one_dragon_context.py
| """ | ||
| 判断某个 OCR 模型的文件是否已经全部就绪 | ||
| """ | ||
| return all(Path(f).exists() for f in get_final_file_list(ocr_model_name)) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 8 \
'get_final_file_list|get_ocr_model_dict_name|dict\.txt|character_dict|def init_model' \
src/one_dragon/base/matcher/ocr || trueRepository: OneDragon-Anything/ZenlessZoneZero-OneDragon
Length of output: 10366
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== one_dragon_context around _is_ocr_model_ready =="
fd -a 'one_dragon_context.py' . | while read -r f; do
echo "--- $f"
wc -l "$f"
sed -n '520,570p' "$f"
done
echo "== onnx_ocr_matcher get_final_file_list and model init =="
sed -n '54,72p' src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py
sed -n '74,180p' src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py
sed -n '200,290p' src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py
echo "== usages of _is_ocr_model_ready / get_final_file_list =="
rg -n '_is_ocr_model_ready|get_final_file_list\(' src/one_dragon || true
echo "== common downloader check_existed semantics =="
fd -a '.*downloader.*\.py' src/one_dragon | while read -r f; do
echo "--- $f"
rg -n -C 5 'check_existed|check_existed_list|exists|is_file|skip_if_existed' "$f" || true
doneRepository: OneDragon-Anything/ZenlessZoneZero-OneDragon
Length of output: 16743
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== dict usage around model loading =="
fd -i '*onnx*ocr*.py' src/one_dragon base | while read -r f; do
echo "--- $f"
rg -n -C 6 '_dict|dict_name|character_dict|PaddleOCR|ONNXPaddleOcr|rec_config|det|rec|cls' "$f" || true
done
echo "== download URLs / expected files =="
rg -n -C 4 'PPOCRV6_MODEL_NAME|DEFAULT_OCR_MODEL_NAME|ocr_model_dir|get_ocr_download_url|_dict\.txt|simfang\.ttf' src tests .github docs README* ipp* 2>/dev/null || trueRepository: OneDragon-Anything/ZenlessZoneZero-OneDragon
Length of output: 564
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== dict/model config usages =="
rg -n -C 6 '_dict|dict_name|character_dict|PaddleOCR|ONNXPaddleOcr|rec_config|det_config|cls_config|skip_crnn' src/one_dragon || true
echo "== OCR model names and file expectations =="
rg -n -C 4 'PPOCRV6_MODEL_NAME|DEFAULT_OCR_MODEL_NAME|ocr_model_dir|get_ocr_download_url|_dict\.txt|simfang\.ttf|det\.onnx|rec\.onnx|cls\.onnx' src/one_dragon tests .github README* docs ipp* 2>/dev/null || true
echo "== common path semantics probe =="
tmp="$(mktemp -d)"
python3 - <<'PY' "$tmp" | sed 's#$tmp#<tmp>`#g`'
import sys, pathlib, os
tmp = pathlib.Path(sys.argv[1])
(p := tmp/'pathy_dir').mkdir(parents=True)
paths = [tmp/'missing', p, tmp/'existing.txt']
for f in paths:
f.touch() if f.name == 'existing.txt' else None
print(f, 'exists=', f.exists(), 'is_file=', f.is_file())
PY
rm -rf "$tmp"Repository: OneDragon-Anything/ZenlessZoneZero-OneDragon
Length of output: 45638
更换 OCR 模型路径的存在性检查为普通文件检查。
_is_ocr_model_ready() 使用 Path.exists(),同名目录也会返回 True,会在下载或解压残留同名目录时错误选择 V6;get_final_file_list() 只在发现 _dict.txt 时才将其加入就绪列表,若字典文件必需则当前逻辑可能漏检。应改用 Path.is_file(),并按实际必需文件范围构造检查列表。
🤖 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 `@src/one_dragon/base/operation/one_dragon_context.py` at line 552, 更新
_is_ocr_model_ready() 的 OCR 模型就绪检查,使用 Path.is_file() 排除同名目录;同时按 OCR
模型实际必需的文件范围构造检查列表,确保必需的 _dict.txt 被纳入校验,不要仅依赖 get_final_file_list() 的条件性收集结果。
为什么改
PR #2515 强制切 v6(默认改 v6、配置立刻改写、下载选项只留 v6),老用户有 v5 也会被强制切走,v6 没下好时 OCR 直接不可用。本改动实现平滑迁移:有 V5 先顶着用,V6 后台下载完成后下次启动再切。
改动要点
关联