Skip to content

建立 OCR 引擎配置中心#843

Merged
xerrors merged 5 commits into
xerrors:mainfrom
Yuchuan925:feat/ocr-config-center
Jul 23, 2026
Merged

建立 OCR 引擎配置中心#843
xerrors merged 5 commits into
xerrors:mainfrom
Yuchuan925:feat/ocr-config-center

Conversation

@Yuchuan925

Copy link
Copy Markdown
Collaborator

变更描述

建立 OCR 引擎配置中心,统一管理 OCR 引擎注册信息、默认参数、启停状态、默认引擎、服务端点和凭证来源。

后端新增 PostgreSQL 持久化配置、加密数据库密钥、脱敏 Redis 快照和跨进程运行时同步;前端新增管理员 OCR 配置页面,并移除上传弹窗中不可达的 OCR 不可用分支。

本次同时按项目维护性要求补齐新增代码的中文 docstring、关键约束注释,并清理 E2E 测试创建的线程、附件和临时对象。

变更类型

  • 新功能
  • Bug 修复
  • 文档更新
  • 其他

设计与影响范围

  • OCR 参数默认值由 Pydantic schema 统一校验和生成,避免注册表与运行时默认值漂移。
  • 自托管引擎允许编辑端点;云服务使用系统管理的官方端点,不允许页面修改。
  • 数据库凭证使用部署级共享密钥加密后保存,凭证不进入接口响应、文件快照或 Redis 快照。
  • DeepSeek OCR 固定复用 siliconflow-cn 模型供应商凭证。
  • API 与 worker 均从 PostgreSQL 同步本地运行时配置,并在配置变化时淘汰旧处理器缓存。
  • 普通用户只获得脱敏 OCR 选项,管理员获得配置编辑能力。

测试

  • 已在 Docker 环境测试
  • 相关功能正常工作

实际执行结果:

  • docker exec api-dev uv run pytest -q test/unit/services/test_ocr_config_service.py test/unit/services/test_ocr_config_cache.py test/unit/knowledge/test_ocr_config_runtime.py test/unit/knowledge/test_parser_facade.py test/unit/services/test_conversation_service_attachment_state.py test/unit/storage/test_postgres_manager_schema.py test/unit/plugins/test_ragflow_like_chunking.py
    • 79 passed, 1 skipped
  • docker exec api-dev uv run pytest -q test/integration/api/test_system_router.py
    • 10 passed
  • docker exec api-dev uv run pytest -q test/e2e/test_ocr_config_center_e2e.py
    • 1 passed,真实 RapidOCR 临时附件链路
  • 相关文件 Ruff、目标文件 C901、git diff --check
    • 通过
  • docker exec web-dev pnpm build
    • 构建成功

已知但未在本 PR 中扩大的项目既有警告:前端 :deep、大 chunk 和 Rolldown 依赖注释警告;unified.py 中既有 _process_file_to_markdown_core C901 复杂度为 22。

Human Review

  • 已完成人工审阅 1 次。
  • 人工检查了全部 diff、任务范围、安全风险、冗余封装、Stepdown Rule、docstring、关键注释和测试结果。

说明

无关联 Issue。当前 PR 按要求创建为 Draft,来源分支为 Yuchuan925/Yuxi:feat/ocr-config-center,目标为 xerrors/Yuxi:main

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@xerrors

xerrors commented Jul 23, 2026

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48d2c7be4b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


@system.get("/ocr/health")
async def get_ocr_health(
current_user: User = Depends(get_required_user),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep OCR health details admin-only

With this dependency change, any authenticated non-admin can call /api/system/ocr/health. That handler runs all health checks and returns parser details such as configured server_url/api_url values and connection errors for MinerU, PP-Structure, DeepSeek, and PaddleOCR; before this diff the same route required get_admin_user. In deployments with internal OCR services or cloud endpoints, this leaks configuration and lets ordinary users trigger server-side health probes, so either keep this endpoint admin-only or return a redacted user-safe status.

Useful? React with 👍 / 👎.

Comment on lines +63 to +69
<OCRSelector
:model-value="item.selectedParseMethod"
:allowed-engines="item.parseMethods"
:disabled="item.status === 'parsing' || confirming"
placeholder="选择 OCR"
@update:model-value="handleParseMethodChange(item.localId, $event)"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore the PDF text-only parse option

For PDF temporary attachments, the backend returns parse_methods including disable, but OCRSelector only adds that synthetic option when includeDisable is true and this call never sets it. As a result, users cannot choose the backend-supported text-layer extraction path for PDFs when the default OCR engine is an OCR service, forcing unnecessary OCR calls for ordinary searchable PDFs. Pass includeDisable here when allowedEngines can contain disable.

Useful? React with 👍 / 👎.

except Exception as e:
return {"status": "error", "message": f"健康检查失败: {str(e)}", "details": {"error": str(e)}}
return {
"status": "configured",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Accept configured health before parsing MinerU Official

When MinerU Official has a configured API key, check_health() now returns configured, but process_file() still rejects every status other than healthy before uploading the file. This means every real mineru_official parse fails immediately with “API 不可用” even though the UI marks the engine usable; either skip that preflight or treat configured as acceptable for this parser.

Useful? React with 👍 / 👎.

const saveOption = async (option) => {
savingOption.value = option.key
try {
const data = await configOptionsApi.updateOption(option.key, draftValue.value)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve existing secret fields when saving other values

When editing the PaddleOCR card to change only api_url, draftValue also contains api_token: '' because sensitive values are intentionally blanked in the serialized option. Sending the whole draft here makes the backend overwrite the stored token with an empty string, so changing the URL silently deletes an existing database token. Omit unchanged sensitive fields or send an explicit clear action only when the user intends to remove the secret.

Useful? React with 👍 / 👎.

Comment on lines +925 to +927
if (
!ocrEngineOptions.value.some((option) => option.value === processingParams.value.ocr_engine)
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't block non-OCR uploads on OCR option loading

This validation runs for every non-URL upload whenever the selected OCR engine is not disable, even if the selected files are plain text or Office documents that never use OCR. If /ocr/options is still loading or fails, users are blocked from adding those non-OCR files with “OCR 引擎选项尚未加载”; gate this check on files that actually need OCR instead of all uploads.

Useful? React with 👍 / 👎.

Comment on lines +6 to +9
<OCRSelector
:model-value="configStore.config?.default_ocr_engine"
@update:model-value="configStore.setConfigValue('default_ocr_engine', $event)"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Expose the disable choice in default OCR settings

The backend still accepts default_ocr_engine: 'disable', and the previous settings UI offered that option, but this new default-OCR selector does not pass includeDisable, so OCRSelector filters the synthetic disable option out. When the current default is an OCR engine, admins can no longer set the global default back to text-only/no-OCR from the settings page; enable the disable option for this settings use case.

Useful? React with 👍 / 👎.

@Yuchuan925
Yuchuan925 marked this pull request as ready for review July 23, 2026 11:39
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@xerrors
xerrors merged commit 311fe67 into xerrors:main Jul 23, 2026
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.

2 participants